diff --git a/.tmp/proof/landing-highlights.png b/.tmp/proof/landing-highlights.png
new file mode 100644
index 0000000..71f8d84
Binary files /dev/null and b/.tmp/proof/landing-highlights.png differ
diff --git a/packages/app/src/components/landing/LandingPage.test.tsx b/packages/app/src/components/landing/LandingPage.test.tsx
index 6381afe..5efd6c8 100644
--- a/packages/app/src/components/landing/LandingPage.test.tsx
+++ b/packages/app/src/components/landing/LandingPage.test.tsx
@@ -31,6 +31,51 @@ describe('LandingPage', () => {
expect(cta).toHaveAttribute('href', '/catalog');
});
+ it('renders the four feature highlights', async () => {
+ await renderInTestApp();
+
+ expect(screen.getByText('What you can try')).toBeInTheDocument();
+ expect(screen.getByText('Software templates')).toBeInTheDocument();
+ expect(screen.getByText('Software catalog')).toBeInTheDocument();
+ expect(screen.getByText('GitHub integration')).toBeInTheDocument();
+ expect(screen.getByText('Answer engine')).toBeInTheDocument();
+ expect(
+ screen.getByText(/Search the catalog and TechDocs in one place/),
+ ).toBeInTheDocument();
+ });
+
+ it('links each highlight to its live surface', async () => {
+ await renderInTestApp();
+
+ expect(
+ screen.getByRole('link', { name: 'Use a template' }),
+ ).toHaveAttribute('href', '/self-service');
+ expect(
+ screen.getByRole('link', { name: 'Browse services' }),
+ ).toHaveAttribute('href', '/catalog');
+ expect(
+ screen.getByRole('link', { name: 'See GitHub integration' }),
+ ).toHaveAttribute('href', '/showcase');
+ expect(
+ screen.getByRole('link', { name: 'Search catalog and docs' }),
+ ).toHaveAttribute('href', '/search');
+ });
+
+ it('renders the footer with a second path into the demo', async () => {
+ await renderInTestApp();
+
+ expect(screen.getByText('Ready to look around?')).toBeInTheDocument();
+ expect(
+ screen.getByText(/The demo runs as a guest with read-only access/),
+ ).toBeInTheDocument();
+ expect(
+ screen.getByRole('link', { name: 'Start with the showcase' }),
+ ).toHaveAttribute('href', '/showcase');
+ expect(
+ screen.getByRole('link', { name: 'Open the catalog' }),
+ ).toHaveAttribute('href', '/catalog');
+ });
+
it('shows the portal screenshot with alt text', async () => {
await renderInTestApp();
diff --git a/packages/app/src/components/landing/LandingPage.tsx b/packages/app/src/components/landing/LandingPage.tsx
index ddaba5a..c1a2138 100644
--- a/packages/app/src/components/landing/LandingPage.tsx
+++ b/packages/app/src/components/landing/LandingPage.tsx
@@ -32,6 +32,43 @@ const ScreenshotFrame = styled('figure')(({ theme }) => ({
},
}));
+const FeatureCard = styled(Box)(({ theme }) => ({
+ display: 'flex',
+ flexDirection: 'column',
+ gap: theme.spacing(1.5),
+ padding: theme.spacing(3),
+ borderRadius: theme.spacing(1),
+ border: `3px solid ${theme.palette.text.primary}`,
+ backgroundColor: theme.palette.background.paper,
+}));
+
+const highlights = [
+ {
+ title: 'Software templates',
+ body: 'Start a service, docs site or AI worker from a template that publishes to GitHub and registers itself in the catalog.',
+ link: '/self-service',
+ linkLabel: 'Use a template',
+ },
+ {
+ title: 'Software catalog',
+ body: 'Every service, API and team in one searchable place, with ownership and lifecycle kept next to the code.',
+ link: '/catalog',
+ linkLabel: 'Browse services',
+ },
+ {
+ title: 'GitHub integration',
+ body: 'Templates open repositories and pull requests, and the catalog stays in sync with what is actually on GitHub.',
+ link: '/showcase',
+ linkLabel: 'See GitHub integration',
+ },
+ {
+ title: 'Answer engine',
+ body: 'Search the catalog and TechDocs in one place. The showcase explains how an answer engine can extend this search foundation.',
+ link: '/search',
+ linkLabel: 'Search catalog and docs',
+ },
+];
+
export const LandingPage = () => {
const theme = useTheme();
@@ -107,6 +144,86 @@ export const LandingPage = () => {
The plugin showcase running live in this portal.
+
+
+
+ What you can try
+
+
+ {highlights.map(highlight => (
+
+
+ {highlight.title}
+
+
+ {highlight.body}
+
+
+
+ ))}
+
+
+
+
+
+ Ready to look around?
+
+
+ The demo runs as a guest with read-only access, so you can open
+ every page without signing up.
+
+
+
+
+
+
);