diff --git a/src/assets/icons/airflow.svg b/src/assets/icons/airflow.svg new file mode 100644 index 0000000..ffb1272 --- /dev/null +++ b/src/assets/icons/airflow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/argo-cd.svg b/src/assets/icons/argo-cd.svg new file mode 100644 index 0000000..fb7bc6f --- /dev/null +++ b/src/assets/icons/argo-cd.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/artifact-hub.svg b/src/assets/icons/artifact-hub.svg new file mode 100644 index 0000000..69a2cbd --- /dev/null +++ b/src/assets/icons/artifact-hub.svg @@ -0,0 +1 @@ +Artifact Hub logo \ No newline at end of file diff --git a/src/assets/icons/authentik.svg b/src/assets/icons/authentik.svg new file mode 100644 index 0000000..c839dda --- /dev/null +++ b/src/assets/icons/authentik.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/cilium.svg b/src/assets/icons/cilium.svg new file mode 100644 index 0000000..56050b8 --- /dev/null +++ b/src/assets/icons/cilium.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/confluence.svg b/src/assets/icons/confluence.svg new file mode 100644 index 0000000..31a7a18 --- /dev/null +++ b/src/assets/icons/confluence.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/consul.svg b/src/assets/icons/consul.svg new file mode 100644 index 0000000..40ac874 --- /dev/null +++ b/src/assets/icons/consul.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/assets/icons/datadog.png b/src/assets/icons/datadog.png new file mode 100644 index 0000000..117ba90 Binary files /dev/null and b/src/assets/icons/datadog.png differ diff --git a/src/assets/icons/datadog.svg b/src/assets/icons/datadog.svg new file mode 100644 index 0000000..76ea1d2 --- /dev/null +++ b/src/assets/icons/datadog.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/drone.svg b/src/assets/icons/drone.svg new file mode 100644 index 0000000..c5a7e6a --- /dev/null +++ b/src/assets/icons/drone.svg @@ -0,0 +1,11 @@ + + + + drone-logo-vector-dark + Created with Sketch. + + + + + + \ No newline at end of file diff --git a/src/assets/icons/elastic-stack.svg b/src/assets/icons/elastic-stack.svg new file mode 100644 index 0000000..05f6c3f --- /dev/null +++ b/src/assets/icons/elastic-stack.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/elasticsearch.svg b/src/assets/icons/elasticsearch.svg new file mode 100644 index 0000000..a338cd6 --- /dev/null +++ b/src/assets/icons/elasticsearch.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/filebeat.svg b/src/assets/icons/filebeat.svg new file mode 100644 index 0000000..402aaa1 --- /dev/null +++ b/src/assets/icons/filebeat.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/assets/icons/gitea.svg b/src/assets/icons/gitea.svg new file mode 100644 index 0000000..4329134 --- /dev/null +++ b/src/assets/icons/gitea.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/harbor.svg b/src/assets/icons/harbor.svg new file mode 100644 index 0000000..bc0e6e7 --- /dev/null +++ b/src/assets/icons/harbor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/headlamp.svg b/src/assets/icons/headlamp.svg new file mode 100644 index 0000000..d7d8975 --- /dev/null +++ b/src/assets/icons/headlamp.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/istio.svg b/src/assets/icons/istio.svg new file mode 100644 index 0000000..c53fdc7 --- /dev/null +++ b/src/assets/icons/istio.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/jaeger.svg b/src/assets/icons/jaeger.svg new file mode 100644 index 0000000..86fb00e --- /dev/null +++ b/src/assets/icons/jaeger.svg @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/jenkins.svg b/src/assets/icons/jenkins.svg new file mode 100644 index 0000000..4a4538d --- /dev/null +++ b/src/assets/icons/jenkins.svg @@ -0,0 +1,283 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/src/assets/icons/jira.svg b/src/assets/icons/jira.svg new file mode 100644 index 0000000..bd440ea --- /dev/null +++ b/src/assets/icons/jira.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/icons/jupyterhub.svg b/src/assets/icons/jupyterhub.svg new file mode 100644 index 0000000..f000235 --- /dev/null +++ b/src/assets/icons/jupyterhub.svg @@ -0,0 +1,75 @@ + + + +Group Copy 2 +Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/kibana.svg b/src/assets/icons/kibana.svg new file mode 100644 index 0000000..8593aa2 --- /dev/null +++ b/src/assets/icons/kibana.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/kong.svg b/src/assets/icons/kong.svg new file mode 100644 index 0000000..ab701d0 --- /dev/null +++ b/src/assets/icons/kong.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/kubeview.png b/src/assets/icons/kubeview.png new file mode 100644 index 0000000..87d74d0 Binary files /dev/null and b/src/assets/icons/kubeview.png differ diff --git a/src/assets/icons/kyverno.svg b/src/assets/icons/kyverno.svg new file mode 100644 index 0000000..41bd9bd --- /dev/null +++ b/src/assets/icons/kyverno.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/logstash.svg b/src/assets/icons/logstash.svg new file mode 100644 index 0000000..919e9b9 --- /dev/null +++ b/src/assets/icons/logstash.svg @@ -0,0 +1,81 @@ + + + + + + image/svg+xml + + Logstash Color Lockup + + + + + + + + Logstash Color Lockup + + + + + + diff --git a/src/assets/icons/nginx.svg b/src/assets/icons/nginx.svg new file mode 100644 index 0000000..ce6146a --- /dev/null +++ b/src/assets/icons/nginx.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/openebs.png b/src/assets/icons/openebs.png new file mode 100644 index 0000000..5aed6ec Binary files /dev/null and b/src/assets/icons/openebs.png differ diff --git a/src/assets/icons/openebs.svg b/src/assets/icons/openebs.svg new file mode 100644 index 0000000..b8f6403 --- /dev/null +++ b/src/assets/icons/openebs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/openmetadata.png b/src/assets/icons/openmetadata.png new file mode 100644 index 0000000..7e79a31 Binary files /dev/null and b/src/assets/icons/openmetadata.png differ diff --git a/src/assets/icons/prometheus.svg b/src/assets/icons/prometheus.svg new file mode 100644 index 0000000..b78f0b4 --- /dev/null +++ b/src/assets/icons/prometheus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/qdrant.svg b/src/assets/icons/qdrant.svg new file mode 100644 index 0000000..82fb8b3 --- /dev/null +++ b/src/assets/icons/qdrant.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/redpanda.svg b/src/assets/icons/redpanda.svg new file mode 100644 index 0000000..5f3162f --- /dev/null +++ b/src/assets/icons/redpanda.svg @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/sonarqube.svg b/src/assets/icons/sonarqube.svg new file mode 100644 index 0000000..c3293af --- /dev/null +++ b/src/assets/icons/sonarqube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/terraform.svg b/src/assets/icons/terraform.svg new file mode 100644 index 0000000..4929cd9 --- /dev/null +++ b/src/assets/icons/terraform.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/traefik.svg b/src/assets/icons/traefik.svg new file mode 100644 index 0000000..7ea849f --- /dev/null +++ b/src/assets/icons/traefik.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/vault.svg b/src/assets/icons/vault.svg new file mode 100644 index 0000000..3562904 --- /dev/null +++ b/src/assets/icons/vault.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/ApplicationsGrid.astro b/src/components/ApplicationsGrid.astro new file mode 100644 index 0000000..f60962f --- /dev/null +++ b/src/components/ApplicationsGrid.astro @@ -0,0 +1,369 @@ +--- +import { Image } from 'astro:assets'; + +import airflowIcon from '@assets/icons/airflow.svg'; +import argoCdIcon from '@assets/icons/argo-cd.svg'; +import artifactHubIcon from '@assets/icons/artifact-hub.svg'; +import authentikIcon from '@assets/icons/authentik.svg'; +import ciliumIcon from '@assets/icons/cilium.svg'; +import confluenceIcon from '@assets/icons/confluence.svg'; +import consulIcon from '@assets/icons/consul.svg'; +import datadogIcon from '@assets/icons/datadog.svg'; +import droneIcon from '@assets/icons/drone.svg'; +import elasticStackIcon from '@assets/icons/elastic-stack.svg'; +import elasticsearchIcon from '@assets/icons/elasticsearch.svg'; +import filebeatIcon from '@assets/icons/filebeat.svg'; +import giteaIcon from '@assets/icons/gitea.svg'; +import harborIcon from '@assets/icons/harbor.svg'; +import headlampIcon from '@assets/icons/headlamp.svg'; +import istioIcon from '@assets/icons/istio.svg'; +import jaegerIcon from '@assets/icons/jaeger.svg'; +import jenkinsIcon from '@assets/icons/jenkins.svg'; +import jiraIcon from '@assets/icons/jira.svg'; +import jupyterhubIcon from '@assets/icons/jupyterhub.svg'; +import kibanaIcon from '@assets/icons/kibana.svg'; +import kongIcon from '@assets/icons/kong.svg'; +import kyvernoIcon from '@assets/icons/kyverno.svg'; +import logstashIcon from '@assets/icons/logstash.svg'; +import nginxIcon from '@assets/icons/nginx.svg'; +import openebsIcon from '@assets/icons/openebs.svg'; +import openmetadataIcon from '@assets/icons/openmetadata.png'; +import prometheusIcon from '@assets/icons/prometheus.svg'; +import qdrantIcon from '@assets/icons/qdrant.svg'; +import redpandaIcon from '@assets/icons/redpanda.svg'; +import sonarqubeIcon from '@assets/icons/sonarqube.svg'; +import terraformIcon from '@assets/icons/terraform.svg'; +import traefikIcon from '@assets/icons/traefik.svg'; +import vaultIcon from '@assets/icons/vault.svg'; + +import { shuffle } from '@utils/helpers.js'; + +interface IconItem { + meta: ImageMetadata; + alt: string; + search: string; + url: string; +} + +const icons: IconItem[] = [ + { meta: airflowIcon, alt: 'Airflow', search: 'airflow', url: 'https://airflow.apache.org/' }, + { meta: argoCdIcon, alt: 'Argo CD', search: 'argo-cd', url: 'https://argoproj.github.io/cd/' }, + { + meta: artifactHubIcon, + alt: 'Artifact Hub', + search: 'artifact-hub', + url: 'https://artifacthub.io/' + }, + { meta: authentikIcon, alt: 'Authentik', search: 'authentik', url: 'https://goauthentik.io/' }, + { meta: ciliumIcon, alt: 'Cilium', search: 'cilium', url: 'https://cilium.io/' }, + { + meta: confluenceIcon, + alt: 'Confluence', + search: 'confluence', + url: 'https://www.atlassian.com/software/confluence' + }, + { meta: consulIcon, alt: 'Consul', search: 'consul', url: 'https://www.consul.io/' }, + { meta: datadogIcon, alt: 'Datadog', search: 'datadog', url: 'https://www.datadoghq.com/' }, + { meta: droneIcon, alt: 'Drone', search: 'drone', url: 'https://www.drone.io/' }, + { + meta: elasticStackIcon, + alt: 'Elastic Stack', + search: 'elastic-stack', + url: 'https://www.elastic.co/elastic-stack' + }, + { + meta: elasticsearchIcon, + alt: 'Elasticsearch', + search: 'elasticsearch', + url: 'https://www.elastic.co/elasticsearch' + }, + { + meta: filebeatIcon, + alt: 'Filebeat', + search: 'filebeat', + url: 'https://www.elastic.co/beats/filebeat' + }, + { meta: giteaIcon, alt: 'Gitea', search: 'gitea', url: 'https://about.gitea.com/' }, + { meta: harborIcon, alt: 'Harbor', search: 'harbor', url: 'https://goharbor.io/' }, + { meta: headlampIcon, alt: 'Headlamp', search: 'headlamp', url: 'https://headlamp.dev/' }, + { meta: istioIcon, alt: 'Istio', search: 'istiod', url: 'https://istio.io/' }, + { meta: jaegerIcon, alt: 'Jaeger', search: 'jaeger', url: 'https://www.jaegertracing.io/' }, + { meta: jenkinsIcon, alt: 'Jenkins', search: 'jenkins', url: 'https://www.jenkins.io/' }, + { meta: jiraIcon, alt: 'Jira', search: 'jira', url: 'https://www.atlassian.com/software/jira' }, + { meta: jupyterhubIcon, alt: 'JupyterHub', search: 'jupyterhub', url: 'https://jupyter.org/hub' }, + { meta: kibanaIcon, alt: 'Kibana', search: 'kibana', url: 'https://www.elastic.co/kibana' }, + { meta: kongIcon, alt: 'Kong', search: 'kong', url: 'https://konghq.com/' }, + { meta: kyvernoIcon, alt: 'Kyverno', search: 'kyverno', url: 'https://kyverno.io/' }, + { + meta: logstashIcon, + alt: 'Logstash', + search: 'logstash', + url: 'https://www.elastic.co/logstash' + }, + { meta: nginxIcon, alt: 'Nginx', search: 'nginx', url: 'https://nginx.org/' }, + { meta: openebsIcon, alt: 'OpenEBS', search: 'openebs', url: 'https://openebs.io/' }, + { + meta: openmetadataIcon, + alt: 'OpenMetadata', + search: 'openmetadata', + url: 'https://open-metadata.org/' + }, + { meta: prometheusIcon, alt: 'Prometheus', search: 'prometheus', url: 'https://prometheus.io/' }, + { meta: qdrantIcon, alt: 'Qdrant', search: 'qdrant', url: 'https://qdrant.tech/' }, + { meta: redpandaIcon, alt: 'Redpanda', search: 'redpanda', url: 'https://redpanda.com/' }, + { + meta: sonarqubeIcon, + alt: 'SonarQube', + search: 'sonarqube', + url: 'https://www.sonarsource.com/products/sonarqube/' + }, + { meta: terraformIcon, alt: 'Terraform', search: 'terraform', url: 'https://www.terraform.io/' }, + { meta: traefikIcon, alt: 'Traefik', search: 'traefik', url: 'https://traefik.io/' }, + { meta: vaultIcon, alt: 'Vault', search: 'vault', url: 'https://www.vaultproject.io/' } +]; + +// Shuffle icons and split into 3 rows +const shuffledIcons: IconItem[] = shuffle(icons); +const iconsPerRow: number = Math.ceil(shuffledIcons.length / 3); +const row1: IconItem[] = shuffledIcons.slice(0, iconsPerRow); +const row2: IconItem[] = shuffledIcons.slice(iconsPerRow, iconsPerRow * 2); +const row3: IconItem[] = shuffledIcons.slice(iconsPerRow * 2); + +const infiniteIconsRow1: IconItem[] = [...row1, ...row1]; +const infiniteIconsRow2: IconItem[] = [...row2, ...row2]; +const infiniteIconsRow3: IconItem[] = [...row3, ...row3]; +--- + +
+ +
+
+ { + infiniteIconsRow1.map((icon: IconItem) => ( + + {icon.alt} + {icon.alt} + + )) + } +
+
+ + +
+
+ { + infiniteIconsRow2.map((icon: IconItem) => ( + + {icon.alt} + {icon.alt} + + )) + } +
+
+ + +
+
+ { + infiniteIconsRow3.map((icon: IconItem) => ( + + {icon.alt} + {icon.alt} + + )) + } +
+
+
+ + diff --git a/src/content/docs/index.mdx b/src/content/docs/index.mdx index 4ab62a3..41b42b4 100644 --- a/src/content/docs/index.mdx +++ b/src/content/docs/index.mdx @@ -54,3 +54,11 @@ import { Icon } from '@astrojs/starlight/components'; Multi-node deployment with automatic failover + +## Explore Application Store + +import IntegrationGrid from '@components/ApplicationsGrid.astro'; + +**Vast Application Ecosystem** — Deploy complex applications easily from our curated store. Tap into a vast ecosystem of integrations to power any stack, anywhere. [Explore the Application Store](/service/applications/04-store/). + + diff --git a/src/utils/helpers.js b/src/utils/helpers.js new file mode 100644 index 0000000..b08016b --- /dev/null +++ b/src/utils/helpers.js @@ -0,0 +1,50 @@ +/** + * Determine if the current Astro request is the homepage (global or localized). + * Mirrors logic: + * pathname === `/${Astro.locals.starlightRoute.locale}/` || pathname === "/" + * @param {any} Astro - The Astro global passed from a .astro file. + * @returns {boolean} + */ +export function isHomepage(Astro) { + const pathname = Astro?.url?.pathname || "/"; + const locale = Astro?.locals?.starlightRoute?.locale; + + return pathname === "/" || (locale ? pathname === `/${locale}/` : false); +} + +/** + * Shuffle an array using the Fisher-Yates algorithm. + * @template T + * @param {T[]} array - The array to shuffle. + * @returns {T[]} - The shuffled array. + */ +export function shuffle(array) { + let arr = [...array]; + for (let i = arr.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + return arr; +} + +/** + * Generates a friendly searchable name from an Aspire NuGet package ID. + * Removes 'Aspire.Hosting.' prefix, replaces dots with hyphens, and converts to lowercase. Based on: https://github.com/dotnet/aspire/blob/main/src/Aspire.Cli/Commands/AddCommand.cs#L254-L261 + * + * @param {string} packageId - The full NuGet package ID (e.g., "Aspire.Hosting.Azure.AppContainers") + * @returns {string} The friendly name (e.g., "azure-appcontainers") + * + * @example + * generateFriendlyName("Aspire.Hosting.Azure.Redis") // Returns: "azure-redis" + * generateFriendlyName("Aspire.Hosting.Postgres") // Returns: "postgres" + * generateFriendlyName("CommunityToolkit.Aspire.Hosting.Cosmos") // Returns: "communitytoolkit-cosmos" + */ +export function generateFriendlyName(packageId) { + // Remove 'Aspire.Hosting.' segment from anywhere in the package name (case-insensitive) + const withoutPrefix = packageId.replace(/Aspire\.Hosting\./gi, ''); + + // Replace dots with hyphens and convert to lowercase + const friendlyName = withoutPrefix.replace(/\./g, '-').toLowerCase(); + + return friendlyName; +} \ No newline at end of file diff --git a/src/utils/imageImporter.js b/src/utils/imageImporter.js new file mode 100644 index 0000000..64fdd04 --- /dev/null +++ b/src/utils/imageImporter.js @@ -0,0 +1,41 @@ +/** + * This module provides functions to help with image importing in Astro. + * It solves the problem of dynamic imports from JSON data. + */ + +// Import all images from the testimonials directory +// This uses Vite's import.meta.glob feature +const testimonialImages = import.meta.glob('../assets/testimonials/*.{png,jpg,jpeg,webp}', { eager: true }); + +/** + * Get an imported image by path + * @param {string} path - The path to the image (e.g., "../assets/testimonials/image.png") + * @returns {string} The processed image URL or the original path if not found + */ +export function getImageByPath(path) { + if (!path || typeof path !== 'string' || !path.startsWith('../assets/')) { + return path; + } + + const importedImage = testimonialImages[path]; + + return importedImage?.default || path; +} + +/** + * Process an array of objects with avatar properties to use imported images + * @param {Array} items - Array of objects containing avatar properties + * @returns {Array} The processed array with imported images + */ +export function processAvatars(items) { + if (!Array.isArray(items)) return []; + + return items.map(item => { + if (!item || typeof item !== 'object') return item; + + return { + ...item, + avatar: getImageByPath(item.avatar) + }; + }); +} diff --git a/tsconfig.json b/tsconfig.json index ca78685..cd5db8a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,12 @@ "include": [".astro/types.d.ts", "**/*"], "exclude": ["dist"], "compilerOptions": { - "types": ["unplugin-icons/types/astro"] + "types": ["unplugin-icons/types/astro"], + "paths": { + "@assets/*": ["./src/assets/*"], + "@components/*": ["./src/components/*"], + "@utils/*": ["./src/utils/*"], + } } + }