Skip to content

Commit d5fd2a1

Browse files
HarshCasperquetzalliwritesremotesynth
authored
feat: azure docs (#468)
Co-authored-by: Quetzalli <hola@quetzalliwrites.com> Co-authored-by: Brian Rinaldi <brian.rinaldi@gmail.com>
1 parent bc3079d commit d5fd2a1

File tree

74 files changed

+22744
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+22744
-3
lines changed

astro.config.mjs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ export default defineConfig({
186186
starlightLlmsTxt({
187187
projectName: 'LocalStack',
188188
description:
189-
'LocalStack is a cloud service emulator that runs in a single container on your laptop or in your CI environment. It provides an easy-to-use test/mocking framework for developing cloud applications, with support for AWS services and Snowflake.',
189+
'LocalStack is a cloud service emulator that runs in a single container on your laptop or in your CI environment. It provides an easy-to-use test/mocking framework for developing cloud applications, with support for AWS services, Snowflake, and Azure.',
190190
customSets: [
191191
{
192192
label: 'AWS',
@@ -198,8 +198,13 @@ export default defineConfig({
198198
description: 'Documentation for LocalStack Snowflake emulation',
199199
paths: ['snowflake/**'],
200200
},
201+
{
202+
label: 'Azure',
203+
description: 'Documentation for LocalStack Azure emulation',
204+
paths: ['azure/**'],
205+
},
201206
],
202-
exclude: ['aws/changelog', 'snowflake/changelog'],
207+
exclude: ['aws/changelog', 'snowflake/changelog', 'azure/changelog'],
203208
rawContent: true,
204209
}),
205210
starlightImageZoom({
@@ -210,7 +215,7 @@ export default defineConfig({
210215
}),
211216
starlightLinksValidator({
212217
errorOnRelativeLinks: true,
213-
errorOnLocalLinks: false, // Allow localhost links in tutorials (they're instructional)
218+
errorOnLocalLinks: false, // Allow localhost links in tutorials (they're instructional)
214219
errorOnInvalidHashes: true,
215220
}),
216221
starlightUtils({
@@ -547,6 +552,34 @@ export default defineConfig({
547552
},
548553
],
549554
},
555+
{
556+
label: 'Azure',
557+
collapsed: true,
558+
items: [
559+
{
560+
label: 'Welcome',
561+
slug: 'azure',
562+
},
563+
{
564+
label: 'Getting Started',
565+
autogenerate: { directory: 'azure/getting-started' },
566+
collapsed: true,
567+
},
568+
{
569+
label: 'Local Azure Services',
570+
slug: 'azure/services',
571+
},
572+
{
573+
label: 'Integrations',
574+
autogenerate: { directory: 'azure/integrations' },
575+
collapsed: true,
576+
},
577+
{
578+
label: 'Changelog',
579+
slug: 'azure/changelog',
580+
},
581+
],
582+
},
550583
],
551584
}),
552585
markdoc(),

public/js/icon-loader.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
Welcome: 'cube-icon',
88
'Getting Started': 'rocket-icon',
99
'Local AWS Services': 'cube-icon',
10+
'Local Azure Services': 'cube-icon',
1011
Features: 'cube-icon',
1112
'Feature Coverage': 'buildings-icon',
1213
'Sample Apps': 'file-icon',
@@ -101,6 +102,8 @@
101102
window.location.href = '/aws/';
102103
} else if (selectedValue === 'Snowflake') {
103104
window.location.href = '/snowflake/';
105+
} else if (selectedValue === 'Azure') {
106+
window.location.href = '/azure/';
104107
}
105108

106109
setTimeout(() => {

src/components/LanguageSelectWithGetStarted.astro

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ import Default from '@astrojs/starlight/components/LanguageSelect.astro';
44
// Get the current page route
55
const route = Astro.locals.starlightRoute;
66
const isSnowflakePage = route.id.startsWith('snowflake');
7+
const isAzurePage = route.id.startsWith('azure');
78
89
let getStartedUrl = 'https://app.localstack.cloud/sign-up';
910
1011
if (isSnowflakePage) {
1112
getStartedUrl += '?emulator=snowflake';
13+
} else if (isAzurePage) {
14+
getStartedUrl += '?emulator=azure';
1215
}
1316
---
1417

src/components/PageTitleWithCopyButton.astro

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,17 @@ const hiddenPaths = [
2222
'snowflake/sample-apps',
2323
'snowflake/capabilities',
2424
'snowflake/integrations',
25+
'azure',
26+
'azure/services',
27+
'azure/sample-apps',
28+
'azure/integrations',
2529
];
2630
2731
// Check if copy page should be hidden (via frontmatter or path match)
2832
const isHiddenPath = hiddenPaths.includes(route.id);
2933
const hideCopyPage = route.entry?.data?.hideCopyPage ?? isHiddenPath;
3034
35+
3136
// Construct the full page URL
3237
const siteUrl = Astro.site?.toString().replace(/\/$/, '') || 'https://docs.localstack.cloud';
3338
const pageUrl = `${siteUrl}/${route.id}/`;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
---
2+
import { getCollection } from 'astro:content';
3+
import { SearchableAzureServices } from './SearchableAzureServices.tsx';
4+
5+
const allServices = await getCollection('docs', ({ id }) => {
6+
return id.startsWith('azure/services/') && !id.includes('/index');
7+
});
8+
9+
const sortedServices = allServices.sort((a, b) => {
10+
const titleA = a.data.title || a.data.linkTitle || '';
11+
const titleB = b.data.title || b.data.linkTitle || '';
12+
return titleA.localeCompare(titleB);
13+
});
14+
15+
const serviceData = sortedServices.map((service) => {
16+
const title = service.data.title || service.data.linkTitle || 'Unknown Service';
17+
const description = service.data.description || `Implementation details for ${title} API`;
18+
const href = `/${service.id}`;
19+
20+
return {
21+
title,
22+
description,
23+
href,
24+
};
25+
});
26+
---
27+
28+
<SearchableAzureServices services={serviceData} client:load />
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import React, { useMemo, useState } from 'react';
2+
import { ServiceBox } from './ServiceBox.tsx';
3+
4+
interface Service {
5+
title: string;
6+
description: string;
7+
href: string;
8+
}
9+
10+
interface SearchableAzureServicesProps {
11+
services: Service[];
12+
}
13+
14+
export const SearchableAzureServices: React.FC<SearchableAzureServicesProps> = ({
15+
services,
16+
}) => {
17+
const [searchTerm, setSearchTerm] = useState('');
18+
19+
const filteredServices = useMemo(() => {
20+
if (!searchTerm.trim()) {
21+
return services;
22+
}
23+
24+
const lowercaseSearch = searchTerm.toLowerCase();
25+
return services.filter(
26+
(service) =>
27+
service.title.toLowerCase().includes(lowercaseSearch) ||
28+
service.description.toLowerCase().includes(lowercaseSearch)
29+
);
30+
}, [services, searchTerm]);
31+
32+
return (
33+
<div className="searchable-services">
34+
<div className="search-container">
35+
<div className="search-input-wrapper">
36+
<svg
37+
className="search-icon"
38+
fill="none"
39+
stroke="currentColor"
40+
viewBox="0 0 24 24"
41+
xmlns="http://www.w3.org/2000/svg"
42+
>
43+
<path
44+
strokeLinecap="round"
45+
strokeLinejoin="round"
46+
strokeWidth={2}
47+
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
48+
/>
49+
</svg>
50+
<input
51+
type="text"
52+
placeholder="Search for Azure Service Name ..."
53+
value={searchTerm}
54+
onChange={(e) => setSearchTerm(e.target.value)}
55+
className="search-input"
56+
/>
57+
</div>
58+
</div>
59+
60+
{filteredServices.length === 0 && searchTerm.trim() ? (
61+
<div className="no-results">
62+
<p>No services found matching "{searchTerm}"</p>
63+
</div>
64+
) : (
65+
<div className="service-grid">
66+
{filteredServices.map((service, index) => (
67+
<ServiceBox
68+
key={`${service.href}-${index}`}
69+
title={service.title}
70+
description={service.description}
71+
href={service.href}
72+
/>
73+
))}
74+
</div>
75+
)}
76+
</div>
77+
);
78+
};

0 commit comments

Comments
 (0)