From dccbb5a6950f75077acf41d7378e0ded6d663a24 Mon Sep 17 00:00:00 2001 From: Harsh Mishra Date: Fri, 20 Jun 2025 22:08:52 +0530 Subject: [PATCH] add search functionality for aws service docs --- src/components/SearchableAwsServices.astro | 29 +++++++++ src/components/SearchableAwsServices.tsx | 75 ++++++++++++++++++++++ src/content/docs/aws/services/index.mdx | 4 +- src/styles/global.css | 59 +++++++++++++++++ 4 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 src/components/SearchableAwsServices.astro create mode 100644 src/components/SearchableAwsServices.tsx diff --git a/src/components/SearchableAwsServices.astro b/src/components/SearchableAwsServices.astro new file mode 100644 index 00000000..d3c6fe72 --- /dev/null +++ b/src/components/SearchableAwsServices.astro @@ -0,0 +1,29 @@ +--- +import { getCollection } from 'astro:content'; +import { SearchableAwsServices } from './SearchableAwsServices.tsx'; + +const allServices = await getCollection('docs', ({ id }) => { + return id.startsWith('aws/services/') && !id.includes('/index'); +}); + +const sortedServices = allServices.sort((a, b) => { + const titleA = a.data.title || a.data.linkTitle || ''; + const titleB = b.data.title || b.data.linkTitle || ''; + return titleA.localeCompare(titleB); +}); + +const serviceData = sortedServices.map(service => { + const title = service.data.title || service.data.linkTitle || 'Unknown Service'; + const description = service.data.description || `Implementation details for ${title} API`; + + const href = `/${service.id}`; + + return { + title, + description, + href + }; +}); +--- + + \ No newline at end of file diff --git a/src/components/SearchableAwsServices.tsx b/src/components/SearchableAwsServices.tsx new file mode 100644 index 00000000..9b25cad8 --- /dev/null +++ b/src/components/SearchableAwsServices.tsx @@ -0,0 +1,75 @@ +import React, { useState, useMemo } from 'react'; +import { ServiceBox } from './ServiceBox.tsx'; + +interface Service { + title: string; + description: string; + href: string; +} + +interface SearchableAwsServicesProps { + services: Service[]; +} + +export const SearchableAwsServices: React.FC = ({ services }) => { + const [searchTerm, setSearchTerm] = useState(''); + + const filteredServices = useMemo(() => { + if (!searchTerm.trim()) { + return services; + } + + const lowercaseSearch = searchTerm.toLowerCase(); + return services.filter(service => + service.title.toLowerCase().includes(lowercaseSearch) || + service.description.toLowerCase().includes(lowercaseSearch) + ); + }, [services, searchTerm]); + + return ( +
+
+
+ + + + setSearchTerm(e.target.value)} + className="search-input" + /> +
+
+ + {filteredServices.length === 0 && searchTerm.trim() ? ( +
+

No services found matching "{searchTerm}"

+
+ ) : ( +
+ {filteredServices.map((service, index) => ( + + ))} +
+ )} +
+ ); +}; \ No newline at end of file diff --git a/src/content/docs/aws/services/index.mdx b/src/content/docs/aws/services/index.mdx index b3584cfc..2b655e9e 100644 --- a/src/content/docs/aws/services/index.mdx +++ b/src/content/docs/aws/services/index.mdx @@ -6,8 +6,8 @@ sidebar: order: 3 --- -import DynamicAwsServices from '../../../../components/DynamicAwsServices.astro'; +import SearchableAwsServices from '../../../../components/SearchableAwsServices.astro'; Browse LocalStack's implemented AWS services and explore their comprehensive feature sets. Each service provides detailed documentation on APIs, configuration options, and practical examples to help you get started quickly. - + diff --git a/src/styles/global.css b/src/styles/global.css index 1c5f7078..65b123b2 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -49,3 +49,62 @@ gap: 1rem; margin-top: 2rem; } + +/* Search styles */ +.searchable-services { + margin-top: 2rem; +} + +.search-container { + margin-bottom: 2rem; +} + +.search-input-wrapper { + position: relative; + max-width: 600px; + margin: 0 auto; +} + +.search-icon { + position: absolute; + left: 1rem; + top: 50%; + transform: translateY(-50%); + width: 1.25rem; + height: 1.25rem; + color: var(--sl-color-gray-3); + pointer-events: none; + z-index: 1; +} + +.search-input { + width: 100%; + padding: 1rem 1rem 1rem 3rem; + border: 2px solid var(--sl-color-gray-5); + border-radius: 2rem; + background-color: var(--sl-color-bg-nav); + color: var(--sl-color-white); + font-size: 1rem; + transition: all 0.2s ease; + outline: none; +} + +.search-input::placeholder { + color: var(--sl-color-gray-3); +} + +.search-input:focus { + border-color: var(--sl-color-accent); + box-shadow: 0 0 0 3px rgba(var(--sl-color-accent-rgb), 0.1); +} + +.no-results { + text-align: center; + padding: 2rem; + color: var(--sl-color-gray-2); +} + +.no-results p { + margin: 0; + font-size: 1.125rem; +}