Skip to content
206 changes: 206 additions & 0 deletions app/components/QuickStartTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
"use client";

import Link from "next/link";
import { useRef, useState } from "react";
import CommandSnippet from "./CommandSnippet";

export type QuickStartStep = {
step: string;
description: string;
};

type QuickStartTabsProps = {
dockerCommand: string;
dockerSteps: QuickStartStep[];
vscodeSteps: QuickStartStep[];
/** Deep link that opens the extension's DocumentDB Local setup wizard. */
vscodeDeepLinkUrl: string;
/** Marketplace page, for visitors who do not have the extension yet. */
vscodeMarketplaceUrl: string;
/** Full guide for each path, linked from the footer of the matching panel. */
dockerDocsUrl: string;
vscodeDocsUrl: string;
};

// "Terminal" rather than "Docker": both paths run the same Docker container, and labelling one
// of them "Docker" implies the other avoids it.
const TABS = [
{ id: "terminal", label: "Terminal" },
{ id: "vscode", label: "VS Code" },
] as const;

type TabId = (typeof TABS)[number]["id"];

function StepList({ steps }: { steps: QuickStartStep[] }) {
return (
<ol className="mt-5 overflow-hidden rounded-2xl border border-neutral-800/80 bg-neutral-900/50">
{steps.map((item) => (
<li
key={item.step}
className="grid grid-cols-[auto_1fr] items-start gap-3 border-t border-neutral-800/80 px-4 py-3.5 first:border-t-0"
>
<span className="inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full border border-blue-400/30 bg-blue-500/10 text-[11px] font-semibold text-blue-200">
{item.step}
</span>
<p className="text-sm leading-6 text-gray-300">{item.description}</p>
</li>
))}
</ol>
);
}

export default function QuickStartTabs({
dockerCommand,
dockerSteps,
vscodeSteps,
vscodeDeepLinkUrl,
vscodeMarketplaceUrl,
dockerDocsUrl,
vscodeDocsUrl,
}: QuickStartTabsProps) {
const [activeTab, setActiveTab] = useState<TabId>("terminal");
const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});

const selectTab = (id: TabId) => {
setActiveTab(id);
tabRefs.current[id]?.focus();
};

// Arrow keys move between tabs, which is what a tablist is expected to do; without it the
// only way through is Tab, and that leaves the panel. Home/End jump to the ends, per the
// ARIA authoring practices for tabs.
const onTabKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {
const currentIndex = TABS.findIndex((tab) => tab.id === activeTab);

switch (event.key) {
case "ArrowRight":
case "ArrowLeft": {
event.preventDefault();
const delta = event.key === "ArrowRight" ? 1 : -1;
selectTab(TABS[(currentIndex + delta + TABS.length) % TABS.length].id);
break;
}
case "Home":
event.preventDefault();
selectTab(TABS[0].id);
break;
case "End":
event.preventDefault();
selectTab(TABS[TABS.length - 1].id);
break;
default:
break;
}
};

return (
<div>
<div
role="tablist"
aria-label="Ways to run DocumentDB locally"
className="mb-4 flex w-full rounded-full border border-neutral-700 bg-neutral-900/80 p-1 sm:inline-flex sm:w-auto"
>
{TABS.map((tab) => {
const isActive = tab.id === activeTab;

return (
<button
key={tab.id}
ref={(element) => {
tabRefs.current[tab.id] = element;
}}
type="button"
role="tab"
id={`quickstart-tab-${tab.id}`}
aria-selected={isActive}
aria-controls={`quickstart-panel-${tab.id}`}
// Only the selected tab is in the tab order; arrow keys move between them.
tabIndex={isActive ? 0 : -1}
onClick={() => setActiveTab(tab.id)}
onKeyDown={onTabKeyDown}
// Solid active state so the tablist reads as a control rather than as another
// badge next to the "Quick start" chip and the numbered step markers.
className={`flex-1 rounded-full px-5 py-3 text-sm font-semibold transition-colors sm:flex-none ${
isActive
? "bg-blue-500 text-white"
: "text-gray-400 hover:text-gray-200"
}`}
>
{tab.label}
</button>
);
})}
</div>

<div
role="tabpanel"
id="quickstart-panel-terminal"
aria-labelledby="quickstart-tab-terminal"
hidden={activeTab !== "terminal"}
>
<CommandSnippet command={dockerCommand} label="Docker" />
<StepList steps={dockerSteps} />
<p className="mt-4 text-sm leading-6 text-gray-400">
Prefer to set it up from your editor? Use the{" "}
<button
type="button"
onClick={() => selectTab("vscode")}
className="font-semibold text-blue-300 underline-offset-2 transition-colors hover:text-blue-200 hover:underline"
>
VS Code
</button>{" "}
tab.
</p>
</div>

<div
role="tabpanel"
id="quickstart-panel-vscode"
aria-labelledby="quickstart-tab-vscode"
hidden={activeTab !== "vscode"}
>
<p className="mb-4 text-sm leading-6 text-gray-400">
Needs Docker Desktop or Docker Engine on the same machine as VS Code.
The extension pulls the image, starts it, and saves the connection for
you. It never installs Docker or changes your system.
</p>
<div className="flex flex-col gap-2 sm:flex-row">
<Link
href={vscodeMarketplaceUrl}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center justify-center rounded-lg border border-blue-400/30 bg-blue-500/20 px-4 py-2.5 text-sm font-semibold text-blue-100 transition-colors hover:bg-blue-500/30"
>
Install the extension
</Link>
<Link
href={vscodeDeepLinkUrl}
className="inline-flex items-center justify-center rounded-lg border border-neutral-600 px-4 py-2.5 text-sm font-semibold text-gray-200 transition-colors hover:border-neutral-500 hover:bg-neutral-800"
>
Open setup in VS Code
</Link>
</div>
<StepList steps={vscodeSteps} />
<p className="mt-4 text-sm leading-6 text-gray-400">
If nothing happens, check that the extension is installed and up to
date, then run{" "}
<strong className="font-semibold text-gray-300">
DocumentDB: Set up DocumentDB Local
</strong>{" "}
from the Command Palette.
</p>
</div>

<div className="mt-4 text-sm">
<Link
href={activeTab === "vscode" ? vscodeDocsUrl : dockerDocsUrl}
className="font-semibold text-blue-300 transition-colors hover:text-blue-200"
>
{activeTab === "vscode"
? "Full VS Code guide"
: "Full Docker guide"}
</Link>
</div>
</div>
);
}
84 changes: 44 additions & 40 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import Image from "next/image";
import Link from "next/link";
import CommandSnippet from "./components/CommandSnippet";
import { documentdbKubernetesOperatorQuickStartUrl } from "./services/externalLinks";
import QuickStartTabs from "./components/QuickStartTabs";
import {
documentdbKubernetesOperatorQuickStartUrl,
documentdbVsCodeExtensionMarketplaceUrl,
documentdbVsCodeLocalQuickStartDeepLink,
} from "./services/externalLinks";
import { getMetadata } from "./services/metadataService";
import {
documentdbGitHubForks,
Expand Down Expand Up @@ -39,18 +43,39 @@ const quickRunCommand = `docker run -dt --name documentdb \\
--username <YOUR_USERNAME> \\
--password <YOUR_PASSWORD>`;

const quickStartSteps = [
const dockerQuickStartSteps = [
{
step: "01",
description:
"Run the command above. Docker pulls the image on the first run, so give it about a minute.",
},
{
step: "02",
description:
"Connect on port 10260 with mongosh, any MongoDB driver, or your app.",
},
{
step: "03",
description:
"Run your first query. The Docker guide has connection strings and sample data.",
},
];

const vscodeQuickStartSteps = [
{
step: "01",
description: "Run DocumentDB Local with Docker.",
description:
"Install the free DocumentDB for VS Code extension from the Marketplace.",
},
{
step: "02",
description: "Connect on port 10260 with your app, shell, or client.",
description:
"Select Open setup in VS Code and allow it to open the link. The wizard starts DocumentDB Local with defaults you can review.",
},
{
step: "03",
description: "Continue with the docs or Linux packages for the setup you need.",
description:
"You get a container on port 10260 with generated credentials. Select Open Connection to browse data and run your first query.",
},
];

Expand Down Expand Up @@ -316,7 +341,7 @@ export default function Home() {
<section className="relative overflow-hidden border-b border-neutral-800 bg-gradient-to-b from-neutral-800 via-neutral-900 to-black">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top_right,_rgba(59,130,246,0.2),_transparent_45%),radial-gradient(circle_at_bottom_left,_rgba(16,185,129,0.18),_transparent_45%)]" />
<div className="relative mx-auto max-w-7xl px-4 py-14 sm:px-6 sm:py-20 lg:px-8 lg:py-24">
<div className="grid items-center gap-8 lg:gap-10 xl:grid-cols-[1.15fr_0.85fr]">
<div className="grid items-start gap-8 lg:gap-10 xl:grid-cols-[1.15fr_0.85fr]">
<div className="min-w-0">
<p className="mb-3 text-xs font-semibold uppercase tracking-[0.24em] text-blue-300">
Open source document database
Expand Down Expand Up @@ -372,43 +397,22 @@ export default function Home() {
Quick start
</span>
<h2 className="mt-4 text-xl font-semibold text-white sm:text-2xl">
Run locally with Docker
Run DocumentDB locally
</h2>
<p className="mt-2 text-sm leading-6 text-gray-400">
Start DocumentDB Local with Docker, then connect on port
10260.
Run it from your terminal, or let the VS Code extension set it
up for you. Both start the same DocumentDB Local container.
</p>
</div>
<CommandSnippet command={quickRunCommand} label="Docker" />
<ol className="mt-5 overflow-hidden rounded-2xl border border-neutral-800/80 bg-neutral-900/50">
{quickStartSteps.map((item) => (
<li
key={item.step}
className="grid grid-cols-[auto_1fr] items-center gap-3 border-t border-neutral-800/80 px-4 py-3.5 first:border-t-0"
>
<span className="inline-flex h-7 w-7 items-center justify-center rounded-full border border-blue-400/30 bg-blue-500/10 text-[11px] font-semibold text-blue-200">
{item.step}
</span>
<p className="text-sm leading-6 text-gray-300">
{item.description}
</p>
</li>
))}
</ol>
<div className="mt-4 flex flex-col gap-2 text-sm sm:flex-row sm:flex-wrap sm:items-center sm:gap-4">
<Link
href="/docs/getting-started/docker"
className="font-semibold text-blue-300 transition-colors hover:text-blue-200"
>
Docker quick start
</Link>
<Link
href="/packages"
className="font-semibold text-gray-300 transition-colors hover:text-white"
>
Download packages
</Link>
</div>
<QuickStartTabs
dockerCommand={quickRunCommand}
dockerSteps={dockerQuickStartSteps}
vscodeSteps={vscodeQuickStartSteps}
vscodeDeepLinkUrl={documentdbVsCodeLocalQuickStartDeepLink}
vscodeMarketplaceUrl={documentdbVsCodeExtensionMarketplaceUrl}
dockerDocsUrl="/docs/getting-started/docker"
vscodeDocsUrl="/docs/getting-started/vscode-quickstart"
/>
</div>
</div>
</div>
Expand Down
6 changes: 6 additions & 0 deletions app/services/externalLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ export const documentdbKubernetesOperatorQuickStartUrl =

export const documentdbKubernetesOperatorGitHubUrl =
'https://github.com/documentdb/documentdb-kubernetes-operator';

export const documentdbVsCodeExtensionMarketplaceUrl =
'https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-documentdb';

export const documentdbVsCodeLocalQuickStartDeepLink =
'vscode://ms-azuretools.vscode-documentdb/local';
Loading