Skip to content
Draft
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
159 changes: 159 additions & 0 deletions app/components/QuickStartTabs.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
"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;
};

const TABS = [
{ id: "docker", label: "Docker" },
{ 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-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>
);
}

/**
* The home page quick start, offering the two ways to get a local DocumentDB running.
*
* Docker stays first because it is the path that works everywhere and needs nothing installed
* beyond Docker itself. The VS Code path is newer and shorter — the extension provisions the
* container itself — but only pays off for people who already work in VS Code, so it is offered
* rather than assumed.
*/
export default function QuickStartTabs({
dockerCommand,
dockerSteps,
vscodeSteps,
vscodeDeepLinkUrl,
vscodeMarketplaceUrl,
}: QuickStartTabsProps) {
const [activeTab, setActiveTab] = useState<TabId>("docker");
const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});

// 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.
const onTabKeyDown = (event: React.KeyboardEvent<HTMLButtonElement>) => {
if (event.key !== "ArrowRight" && event.key !== "ArrowLeft") {
return;
}

event.preventDefault();
const currentIndex = TABS.findIndex((tab) => tab.id === activeTab);
const delta = event.key === "ArrowRight" ? 1 : -1;
const next = TABS[(currentIndex + delta + TABS.length) % TABS.length];

setActiveTab(next.id);
tabRefs.current[next.id]?.focus();
};

return (
<div>
<div
role="tablist"
aria-label="Ways to run DocumentDB locally"
className="mb-4 inline-flex rounded-full border border-neutral-700 bg-neutral-900/80 p-1"
>
{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}
className={`rounded-full px-4 py-1.5 text-xs font-semibold transition-colors ${
isActive
? "bg-blue-500/20 text-blue-100"
: "text-gray-400 hover:text-gray-200"
}`}
>
{tab.label}
</button>
);
})}
</div>

<div
role="tabpanel"
id="quickstart-panel-docker"
aria-labelledby="quickstart-tab-docker"
hidden={activeTab !== "docker"}
>
<CommandSnippet command={dockerCommand} label="Docker" />
<StepList steps={dockerSteps} />
</div>

<div
role="tabpanel"
id="quickstart-panel-vscode"
aria-labelledby="quickstart-tab-vscode"
hidden={activeTab !== "vscode"}
>
<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-neutral-600 px-4 py-2.5 text-sm font-semibold text-gray-200 transition-colors hover:border-neutral-500 hover:bg-neutral-800"
>
Get the extension
</Link>
{/*
* A `vscode://` link does nothing at all when VS Code is not installed — no error, no
* navigation — so it is offered second and never on its own. Someone arriving without
* the extension gets the install link first and this becomes the obvious next step.
*/}
<Link
href={vscodeDeepLinkUrl}
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"
>
Open in VS Code
</Link>
</div>
<StepList steps={vscodeSteps} />
</div>
</div>
);
}
56 changes: 34 additions & 22 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,7 +43,7 @@ const quickRunCommand = `docker run -dt --name documentdb \\
--username <YOUR_USERNAME> \\
--password <YOUR_PASSWORD>`;

const quickStartSteps = [
const dockerQuickStartSteps = [
{
step: "01",
description: "Run DocumentDB Local with Docker.",
Expand All @@ -54,6 +58,23 @@ const quickStartSteps = [
},
];

const vscodeQuickStartSteps = [
{
step: "01",
description: "Install the DocumentDB extension for Visual Studio Code.",
},
{
step: "02",
description:
"Open the DocumentDB Local setup and let the extension create and start the container for you.",
},
{
step: "03",
description:
"Browse databases, run queries, and edit documents without leaving the editor.",
},
];

const kubernetesOperatorEntryPoints = [
{
title: "Local clusters",
Expand Down Expand Up @@ -372,29 +393,20 @@ 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.
Start DocumentDB Local with Docker, or let the VS Code
extension set it up for you.
</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>
<QuickStartTabs
dockerCommand={quickRunCommand}
dockerSteps={dockerQuickStartSteps}
vscodeSteps={vscodeQuickStartSteps}
vscodeDeepLinkUrl={documentdbVsCodeLocalQuickStartDeepLink}
vscodeMarketplaceUrl={documentdbVsCodeExtensionMarketplaceUrl}
/>
<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"
Expand Down
14 changes: 14 additions & 0 deletions app/services/externalLinks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,17 @@ 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';

// Deep link into the extension's DocumentDB Local setup wizard.
//
// The path names the action; an empty path means "connect", which is what every link published
// before the extension supported actions relies on. See the extension's
// docs/user-manual/how-to-construct-url.md for the full vocabulary.
//
// Requires the extension to be installed: a `vscode://` URL for an absent extension does nothing
// visible at all, so never present this without the marketplace link beside it.
export const documentdbVsCodeLocalQuickStartDeepLink =
'vscode://ms-azuretools.vscode-documentdb/local';