Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
39 changes: 39 additions & 0 deletions docs/src/components/copy-command.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
const { command, label = 'Copy' } = Astro.props;
---
<div class="copy-command" data-copy-command>
<span class="copy-command-prompt" aria-hidden="true">$</span>
<code class="copy-command-code">{command}</code>
<button
type="button"
class="copy-command-btn"
data-copy-btn
data-command={command}
aria-label={label}
>
<svg class="copy-command-icon copy-command-icon-copy" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
</svg>
<svg class="copy-command-icon copy-command-icon-check" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<polyline points="20 6 9 17 4 12"></polyline>
</svg>
</button>
</div>

<script>
document.querySelectorAll('[data-copy-command]').forEach((el) => {
const btn = el.querySelector<HTMLButtonElement>('[data-copy-btn]');
if (!btn) return;
btn.addEventListener('click', async () => {
const cmd = btn.getAttribute('data-command') ?? '';
try {
await navigator.clipboard.writeText(cmd);
el.classList.add('is-copied');
setTimeout(() => el.classList.remove('is-copied'), 1600);
} catch {
// noop
}
});
});
</script>
134 changes: 134 additions & 0 deletions docs/src/components/generator-carousel.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
---
import { Code } from '@astrojs/starlight/components';

const slides = [
{
title: 'Multi-Agent AI App',
description: 'TypeScript and Python Strands agents and an MCP server.',
commands: [
'pnpm nx g @aws/nx-plugin:ts#project',
'pnpm nx g @aws/nx-plugin:ts#strands-agent',
'pnpm nx g @aws/nx-plugin:py#project',
'pnpm nx g @aws/nx-plugin:py#strands-agent',
'pnpm nx g @aws/nx-plugin:ts#mcp-server',
'pnpm nx g @aws/nx-plugin:connection',
],
},
{
title: 'tRPC Web App with CDK',
description: 'A type-safe tRPC API with a React frontend, Cognito auth, and CDK.',
commands: [
'pnpm nx g @aws/nx-plugin:ts#react-website',
'pnpm nx g @aws/nx-plugin:ts#react-website#auth',
'pnpm nx g @aws/nx-plugin:ts#trpc-api',
'pnpm nx g @aws/nx-plugin:ts#infra',
'pnpm nx g @aws/nx-plugin:connection',
],
},
{
title: 'FastAPI Web App with Terraform',
description: 'A Python FastAPI with a React frontend, Cognito auth, and Terraform.',
commands: [
'pnpm nx g @aws/nx-plugin:py#fast-api',
'pnpm nx g @aws/nx-plugin:ts#react-website',
'pnpm nx g @aws/nx-plugin:ts#react-website#auth',
'pnpm nx g @aws/nx-plugin:terraform#project',
'pnpm nx g @aws/nx-plugin:connection',
],
},
{
title: 'AG-UI Web App',
description: 'A React app with Cognito auth and an AG-UI Strands agent.',
commands: [
'pnpm nx g @aws/nx-plugin:ts#react-website',
'pnpm nx g @aws/nx-plugin:ts#react-website#auth',
'pnpm nx g @aws/nx-plugin:py#project',
'pnpm nx g @aws/nx-plugin:py#strands-agent',
'pnpm nx g @aws/nx-plugin:ts#infra',
'pnpm nx g @aws/nx-plugin:connection',
],
},
];

const generatorIdHighlight = /\:([^\s]+)/g;
---
<div class="gen-carousel" data-gen-carousel>
<div class="gen-carousel-window">
<div class="gen-carousel-chrome" aria-hidden="true">
<span class="gen-carousel-dot gen-carousel-dot--red"></span>
<span class="gen-carousel-dot gen-carousel-dot--yellow"></span>
<span class="gen-carousel-dot gen-carousel-dot--green"></span>
<span class="gen-carousel-chrome-title" data-carousel-title>{slides[0].title}</span>
</div>
<div class="gen-carousel-track" data-carousel-track>
{slides.map((slide, idx) => (
<div class={`gen-carousel-slide${idx === 0 ? ' is-active' : ''}`} data-slide-index={idx}>
<p class="gen-carousel-caption">{slide.description}</p>
<div class="gen-carousel-code">
<Code lang="bash" code={slide.commands.join('\n')} mark={[generatorIdHighlight]} />
</div>
</div>
))}
</div>
</div>
<div class="gen-carousel-controls" role="tablist" aria-label="Example scenarios">
{slides.map((slide, idx) => (
<button
type="button"
class={`gen-carousel-pill${idx === 0 ? ' is-active' : ''}`}
data-carousel-pill
data-slide-target={idx}
role="tab"
aria-selected={idx === 0 ? 'true' : 'false'}
>
{slide.title}
</button>
))}
</div>
</div>

<script>
const carousels = document.querySelectorAll<HTMLElement>('[data-gen-carousel]');
carousels.forEach((carousel) => {
const slides = carousel.querySelectorAll<HTMLElement>('.gen-carousel-slide');
const pills = carousel.querySelectorAll<HTMLButtonElement>('[data-carousel-pill]');
const titleEl = carousel.querySelector<HTMLElement>('[data-carousel-title]');
const titles = Array.from(pills).map((p) => p.textContent ?? '');
let current = 0;
let timer: ReturnType<typeof setInterval> | null = null;

const show = (next: number) => {
slides[current].classList.remove('is-active');
pills[current].classList.remove('is-active');
pills[current].setAttribute('aria-selected', 'false');
current = next;
slides[current].classList.add('is-active');
pills[current].classList.add('is-active');
pills[current].setAttribute('aria-selected', 'true');
if (titleEl) titleEl.textContent = titles[current];
};

const start = () => {
stop();
timer = setInterval(() => show((current + 1) % slides.length), 6000);
};
const stop = () => {
if (timer) {
clearInterval(timer);
timer = null;
}
};

pills.forEach((pill) => {
pill.addEventListener('click', () => {
const idx = Number(pill.getAttribute('data-slide-target'));
show(idx);
start();
});
});

carousel.addEventListener('mouseenter', stop);
carousel.addEventListener('mouseleave', start);
start();
});
</script>
134 changes: 49 additions & 85 deletions docs/src/content/docs/en/index.mdx
Original file line number Diff line number Diff line change
@@ -1,113 +1,77 @@
---
title: '@aws/nx-plugin'
description: Rapidly scaffold and build projects on AWS
description: Rapidly scaffold and build production-ready apps on AWS.
template: splash
hero:
tagline: Rapidly scaffold and build projects on AWS
tagline: Build full-stack AWS apps in minutes, not days.
image:
light: ../assets/bulb-black.svg
dark: ../assets/bulb-white.svg
actions:
- text: Get started
link: get_started/quick-start
icon: right-arrow
- text: Concepts
link: get_started/concepts
icon: right-arrow
variant: primary
- text: Build with AI
link: get_started/building-with-ai
icon: rocket
variant: secondary
- text: Read the NX docs
link: https://nx.dev/getting-started/intro
icon: external
variant: minimal
---

<p class="badges">
<a href="https://opensource.org/licenses/Apache-2.0">
<img
src="https://img.shields.io/badge/License-Apache%202.0-yellowgreen.svg"
alt="Apache 2.0 License"
/>
</a>
<a href="https://codecov.io/gh/awslabs/nx-plugin-for-aws">
<img src="https://codecov.io/gh/awslabs/nx-plugin-for-aws/graph/badge.svg?token=X27pgFfxuQ" />
</a>
<a href="https://gitpod.io/new/?workspaceClass=g1-large#https://github.com/awslabs/nx-plugin-for-aws">
<img
src="https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod"
alt="Gitpod ready-to-code"
/>
</a>
<a href="https://github.com/awslabs/nx-plugin-for-aws/actions/workflows/ci.yml">
<img
src="https://github.com/awslabs/nx-plugin-for-aws/actions/workflows/ci.yml/badge.svg"
alt="Release badge"
/>
</a>
<a href="https://github.com/awslabs/nx-plugin-for-aws/commits/main">
<img
src="https://img.shields.io/github/commit-activity/w/awslabs/nx-plugin-for-aws"
alt="Commit activity"
/>
</a>
</p>

import { CardGrid, Card, Icon, LinkButton } from '@astrojs/starlight/components';
import { ContributorList } from 'starlight-contributor-list';
import { VideoPlayer } from 'starlight-videos/components';
import {
CardGrid,
Card,
Icon,
LinkButton,
} from '@astrojs/starlight/components';
import { Image } from 'astro:assets';
import websiteGeneratorGif from '@assets/website-generator.gif';
import CopyCommand from '@components/copy-command.astro';
import GeneratorCarousel from '@components/generator-carousel.astro';

<div class='container three-column grid-icons'>
##### A collection of Nx Generators for rapidly building cloud-native applications on AWS
<div class="landing-section landing-hero-extras">
<p class="landing-subline">
A collection of Nx generators for rapidly building cloud-native applications on AWS — type-safe, locally runnable, and ready to deploy.
</p>

<CardGrid className="foo">
<Card title="Full-Stack AWS in Minutes, Not Days">
<Icon name="rocket" size="100px"/>
</Card>
<Card title="Type-Safe Across Your Entire Stack">
<Icon name="seti:json" size="100px"/>
</Card>
<Card title="Build AI Agents, APIs, Websites, and More">
<Icon name="puzzle" size="100px"/>
</Card>
</CardGrid>
<div class="landing-install">
<span class="landing-install-label">Create a new workspace</span>
<CopyCommand command="pnpm create @aws/nx-workspace" />
</div>
</div>

<div class='container'>

{/* TODO: Replace the below gif with the watch and learn series */}
{/* ##### Watch and learn series */}
{/* <a href="/videos/course/overview"> */}
{/* <VideoPlayer link="https://www.youtube.com/watch?v=5u0Ds7wzUeI" /> */}
{/* </a> */}

<div style={{ width: '100%' }}>
<Image
style={{ margin: 'auto' }}
src={websiteGeneratorGif}
alt="A short example of using a generator"
width="800"
height="600"
/>
<div class="landing-section landing-carousel-section">
<h2 class="landing-heading">Scaffold anything. Connect it together.</h2>
<p class="landing-lede">
Each generator produces production-ready application code <em>and</em> the infrastructure to deploy it. Run them interactively — you'll be prompted for the values you need.
</p>
<GeneratorCarousel />
</div>

<div class="landing-section">
<h2 class="landing-heading">Why @aws/nx-plugin?</h2>
<CardGrid>
<Card title="Full-stack in minutes" icon="puzzle">
Website, API, auth, agents and infrastructure — all scaffolded and wired together.
</Card>
<Card title="Build with AI" icon="rocket">
An MCP server ships with the plugin so your AI assistant can scaffold and connect projects for you.
</Card>
<Card title="Type-safe, end to end" icon="seti:json">
Shared types flow from your API through to your frontend. Refactor with confidence.
</Card>
<Card title="Your code, your way" icon="setting">
Generators give you a head start, not a framework. The code is yours to read, modify, and extend.
</Card>
</CardGrid>
</div>

<div class="container community-section">
##### Join the community

<div class="landing-section landing-community">
<h2 class="landing-heading">Join the community</h2>
<p>Have questions or want to share feedback?</p>
<p>Join us on the <a href="https://cdk-dev.slack.com/archives/C0AG11EUHM4"><strong>#nx-plugin-for-aws</strong></a> Slack channel to connect with other users and contributors.</p>

<LinkButton href="https://cdk-dev.slack.com/archives/C0AG11EUHM4" icon="slack" variant="secondary">Join us on Slack</LinkButton>
<p>
Join us on the <a href="https://cdk-dev.slack.com/archives/C0AG11EUHM4"><strong>#nx-plugin-for-aws</strong></a> Slack channel to connect with other users and contributors.
</p>
<LinkButton href="https://cdk-dev.slack.com/archives/C0AG11EUHM4" icon="slack" variant="secondary">
Join us on Slack
</LinkButton>
</div>

<div class="container">
##### Thank you to our amazing contributors!
<div class="landing-section">
<h2 class="landing-heading">Thank you to our amazing contributors!</h2>
<ContributorList githubRepo="awslabs/nx-plugin-for-aws" />
</div>
Loading
Loading