diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index e4b04dd1..00000000 --- a/docs/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Topo Documentation - -The source of documentation for the Topo project: - -- [Introduction](./introduction) -- [Project Specification](./project-specification) -- [Development Guide](./development/DEVELOPMENT.md) diff --git a/docs/docs-config.json b/docs/docs-config.json index 8f03c260..fab854f6 100644 --- a/docs/docs-config.json +++ b/docs/docs-config.json @@ -1,5 +1,6 @@ { "siteLabel": "Topo", + "indexPageDirectory": "landing-page", "navbarItems": [ { "label": "Documentation", diff --git a/docs/introduction/README.md b/docs/introduction/README.md index 45cd43e0..0d6bb9e7 100644 --- a/docs/introduction/README.md +++ b/docs/introduction/README.md @@ -12,7 +12,7 @@ You run Topo on a host and deploy to a target. The host can run Linux, macOS, or This diagram shows where Topo runs, what it deploys, and how you iterate on a project. -![Topo host-to-target deployment and development loop](./img/topo-overview.svg) +![Topo host-to-target deployment and development loop](/img/topo-overview.svg) ## Benefits of Topo diff --git a/docs/landing-page/_homepage.ts b/docs/landing-page/_homepage.ts new file mode 100644 index 00000000..bfc11d93 --- /dev/null +++ b/docs/landing-page/_homepage.ts @@ -0,0 +1,109 @@ +export type HomepageLink = { + label: string; + to: string; + external?: boolean; + variant: "primary" | "secondary"; +}; + +export type BottomCard = { + label: string; + title: string; + description: string; + to: string; + cta: string; + variant: "primary" | "secondary"; +}; + +export type CodeExample = { + label: string; + title: string; + description: string; + code: string; +}; + +export const homepageContent = { + meta: { + title: "Topo", + description: + "Discover Arm device capabilities and deploy containerised software over SSH.", + }, + headline: "Build on your laptop. Run on Arm with Topo.", + lead: "Topo discovers Arm device features, automatically filters supported projects, and simplifies configuration and deployment of containerised software over SSH.", + heroLinks: [ + { + label: "Overview", + to: "/introduction", + variant: "primary", + }, + { + label: "View repository", + to: "https://github.com/arm/topo", + external: true, + variant: "secondary", + }, + ] as HomepageLink[], + codeExamples: { + eyebrow: "Topo workflow", + title: "Get your project running in seconds", + subtitle: + "Check device features and health, find compatible projects, and deploy over SSH without replacing your existing container workflow.", + items: [ + { + label: "Check", + title: "Know the target is ready.", + description: + "Verify the host, SSH connection, target, and hardware before deploying.", + code: `topo health --target pi@raspberrypi`, + }, + { + label: "Discover", + title: "Find projects that fit.", + description: + "Match projects to the capabilities available on the target device.", + code: `topo projects --target pi@raspberrypi`, + }, + { + label: "Configure", + title: "Prepare the project.", + description: "Copy and configure a project on the host.", + code: `topo clone https://github.com/Arm-Examples/topo-welcome.git`, + }, + { + label: "Deploy", + title: "Ship over SSH.", + description: + "Configure, build, transfer, and start the Compose project on the target.", + code: `topo deploy --target pi@raspberrypi`, + }, + ] as CodeExample[], + }, + bottomCards: [ + { + label: "Getting started", + title: "Install and deploy with Topo", + description: + "Install Topo, check a target, and deploy your first project.", + to: "/introduction/install", + cta: "Install Topo", + variant: "secondary", + }, + { + label: "Project specification", + title: "Build hardware-aware projects", + description: + "Add Topo metadata to a standard Compose project.", + to: "/project-specification", + cta: "Read the specification", + variant: "secondary", + }, + { + label: "Development", + title: "Contribute to Topo", + description: + "Work on Topo itself and follow the contributor workflow.", + to: "/development", + cta: "Open the guide", + variant: "secondary", + }, + ] as BottomCard[], +}; diff --git a/docs/landing-page/external-link.svg b/docs/landing-page/external-link.svg new file mode 100644 index 00000000..469ef3d9 --- /dev/null +++ b/docs/landing-page/external-link.svg @@ -0,0 +1,9 @@ + + + diff --git a/docs/landing-page/index.module.css b/docs/landing-page/index.module.css new file mode 100644 index 00000000..fc7c6fc3 --- /dev/null +++ b/docs/landing-page/index.module.css @@ -0,0 +1,395 @@ +.page { + background: var(--ifm-background-color); + color: var(--ifm-font-color-base); + min-height: 100vh; +} + +.page h1, +.page h2, +.page h3, +.page h4 { + color: var(--ifm-heading-color); + line-height: 1.2; +} + +.hero { + display: grid; + grid-template-columns: 1fr minmax(520px, 620px); + gap: 2rem; + padding: 4.5rem clamp(1.5rem, 4vw, 2rem); + align-items: center; + position: relative; + overflow: hidden; +} + +.heroContent h1 { + margin: 0.4rem 0 0.6rem; + font-size: clamp(2.6rem, 4vw, 3.4rem); + letter-spacing: -0.02em; + line-height: 1.2; +} + +.lead { + max-width: 640px; + color: var(--ifm-color-content-secondary); + font-size: 1.05rem; + line-height: 1.6; + margin-bottom: 1.5rem; +} + +.lead code { + background: var(--ifm-code-background); + border: 1px solid var(--ifm-color-emphasis-200); + color: var(--ifm-code-color); +} + +.actions { + display: flex; + flex-wrap: wrap; + gap: 0.6rem; +} + +.button { + align-items: center; + display: inline-flex; + font-size: 1rem; + font-weight: 400; +} + +.externalLinkIcon { + flex: 0 0 auto; + height: 1em; + margin-left: 0.4rem; + width: 1em; +} + +.page :global(.button) { + border-radius: 128px; + font-size: 0.875rem; + font-weight: 400; + line-height: 1; + min-height: 2.5rem; + padding: 0.9375rem 1.1875rem; +} + +.page :global(.button--primary), +.page :global(.button--primary):visited { + --ifm-button-background-color: var(--arm-blue); + --ifm-button-border-color: transparent; + --ifm-button-color: #fff; + color: #fff; +} + +.page :global(.button--primary:hover), +.page :global(.button--primary:active) { + --ifm-button-background-color: var(--arm-blue-hover); + --ifm-button-border-color: transparent; + color: #fff; +} + +.page :global(.button--primary:focus) { + --ifm-button-background-color: #0046cc; + --ifm-button-border-color: transparent; + color: #fff; +} + +:global(html[data-theme="dark"]) .page :global(.button--primary), +:global(html[data-theme="dark"]) .page :global(.button--primary):visited { + --ifm-button-background-color: #7233f7; + --ifm-button-border-color: transparent; + --ifm-button-color: #fff; + color: #fff; +} + +:global(html[data-theme="dark"]) .page :global(.button--primary:hover), +:global(html[data-theme="dark"]) .page :global(.button--primary:active) { + --ifm-button-background-color: #6023de; + --ifm-button-border-color: transparent; + color: #fff; +} + +:global(html[data-theme="dark"]) .page :global(.button--primary:focus) { + --ifm-button-background-color: #8047f8; + --ifm-button-border-color: transparent; + color: #fff; +} + +.page :global(.button--secondary), +.page :global(.button--secondary):visited { + --ifm-button-background-color: #f4f8ff; + --ifm-button-border-color: var(--arm-blue-hover); + --ifm-button-color: var(--arm-blue); + color: var(--arm-blue); +} + +.page :global(.button--secondary:hover) { + --ifm-button-background-color: #e6eeff; + --ifm-button-border-color: var(--arm-blue-hover); + color: var(--arm-blue); +} + +.page :global(.button--secondary:focus), +.page :global(.button--secondary:active) { + --ifm-button-background-color: #ebf1ff; + --ifm-button-border-color: var(--arm-blue-hover); + color: var(--arm-blue); +} + +:global(html[data-theme="dark"]) .page :global(.button--secondary), +:global(html[data-theme="dark"]) .page :global(.button--secondary):visited { + --ifm-button-background-color: #080225; + --ifm-button-border-color: #d1bafc; + --ifm-button-color: #d1bafc; + color: #d1bafc; +} + +:global(html[data-theme="dark"]) .page :global(.button--secondary:hover) { + --ifm-button-background-color: #261a4f; + --ifm-button-border-color: #d1bafc; + color: #d1bafc; +} + +:global(html[data-theme="dark"]) .page :global(.button--secondary:focus), +:global(html[data-theme="dark"]) .page :global(.button--secondary:active) { + --ifm-button-background-color: #391a7c; + --ifm-button-border-color: #d1bafc; + color: #d1bafc; +} + +.heroVisual { + display: flex; + flex-direction: column; + z-index: 1; +} + +.heroDiagram { + color: #000; + display: block; + height: auto; + width: 100%; + max-width: 100%; +} + +:global(html[data-theme="dark"]) .heroDiagram { + color: #fff; +} + +@media screen and (min-width: 1440px) { + .hero { + grid-template-columns: 1fr minmax(620px, 900px); + } +} + +.codeSection { + padding: 2.2rem clamp(1.5rem, 4vw, 2rem) 0.9rem; +} + +.codeIntro { + margin-bottom: 1.1rem; + max-width: 760px; +} + +.codeEyebrow { + margin: 0 0 0.2rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--ifm-color-primary); + font-size: 0.78rem; +} + +.codeIntro h2 { + margin: 0 0 0.4rem; + font-size: clamp(1.45rem, 2vw, 1.9rem); +} + +.codeIntro p { + margin: 0; + color: var(--ifm-color-content-secondary); + line-height: 1.5; +} + +.codeGrid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 1rem; +} + +.exampleCard { + background: var(--ifm-background-color); + border: 1px solid var(--arm-grey-30); + border-radius: var(--ifm-card-border-radius); + box-shadow: var(--ifm-global-shadow-lw); + display: flex; + flex-direction: column; + overflow: hidden; +} + +:global(html[data-theme="dark"]) .exampleCard { + border-color: var(--arm-ink-70); +} + +.exampleHead { + flex: 1; + padding: 1rem 1rem 0.85rem; +} + +.exampleTag { + align-items: center; + display: inline-flex; + margin-bottom: 0.55rem; + padding: 0.35rem 0.9rem; + border-radius: 999px; + border: 1px solid var(--ifm-color-emphasis-300); + background: var(--arm-grey-05); + color: var(--ifm-color-emphasis-700); + font-size: 0.85rem; + letter-spacing: 0.02rem; + line-height: 1.5rem; + gap: 0.5rem; +} + +:global(html[data-theme="dark"]) .exampleTag { + background: var(--arm-code-background); + border-color: var(--arm-ink-70); +} + +.exampleHead h3 { + margin: 0 0 0.35rem; + font-size: 1.02rem; +} + +.exampleHead p { + margin: 0; + color: var(--ifm-color-content-secondary); + font-size: 0.9rem; + line-height: 1.45; +} + +.exampleCode { + margin: 0; + padding: 1rem; + background: var(--arm-grey-05); + border-top: 1px solid var(--arm-grey-30); + border-bottom: 1px solid var(--arm-grey-30); + overflow: auto; +} + +.exampleCode code { + background: transparent; + color: #333e48; + font-size: 0.83rem; + line-height: 1.5; + white-space: pre; +} + +:global(html[data-theme="dark"]) .exampleCode { + background: var(--arm-code-background); + border-color: var(--arm-code-border); +} + +:global(html[data-theme="dark"]) .exampleCode code { + color: var(--arm-code-foreground); +} + +.bottom { + display: grid; + grid-template-columns: 1fr; + gap: 1rem; + padding: 2rem clamp(1.5rem, 4vw, 2rem) 3.2rem; +} + +.bottomCard { + background: var(--ifm-card-background-color); + border: 1px solid var(--arm-grey-30); + border-radius: var(--ifm-card-border-radius); + padding: 1.4rem; + display: flex; + justify-content: space-between; + align-items: center; + gap: 1rem; + box-shadow: var(--ifm-global-shadow-lw); +} + +.bottomCardLink, +.bottomCardLink:active, +.bottomCardLink:visited { + color: inherit; + text-decoration: none; +} + +.bottomCardLink { + transition: all var(--ifm-transition-fast) ease; + transition-property: border, box-shadow; +} + +.bottomCardLink:hover { + color: inherit; + text-decoration: none; + border-color: var(--ifm-color-primary); + box-shadow: 0 3px 6px 0 rgba(0, 0, 0, 0.2); +} + +.bottomCardLink:focus-visible { + outline: calc(var(--ifm-global-border-width) * 2) solid + var(--ifm-color-primary); + outline-offset: calc(var(--ifm-global-border-width) * 2); +} + +:global(html[data-theme="dark"]) .bottomCard { + border-color: var(--arm-ink-70); +} + +:global(html[data-theme="dark"]) .bottomCardLink:hover { + border-color: var(--ifm-color-primary); +} + +.bottomCard h4 { + margin: 0 0 1rem; +} + +.label { + text-transform: uppercase; + letter-spacing: 0.08em; + font-size: 0.75rem; + color: var(--ifm-color-primary); + margin: 0 0 0.2rem; +} + +.small { + color: var(--ifm-color-content-secondary); + margin: 0.1rem 0 0; + line-height: 1.4; +} + +@media screen and (max-width: 960px) { + .hero { + display: flex; + flex-direction: column; + } + + .heroContent { + display: contents; + } + + .heroContent h1 { + order: 1; + } + + .lead { + order: 2; + } + + .heroVisual { + order: 3; + } + + .actions { + order: 4; + } +} + +@media screen and (max-width: 640px) { + .codeGrid { + grid-template-columns: 1fr; + } +} diff --git a/docs/landing-page/index.tsx b/docs/landing-page/index.tsx new file mode 100644 index 00000000..2cce616b --- /dev/null +++ b/docs/landing-page/index.tsx @@ -0,0 +1,106 @@ +import Link from "@docusaurus/Link"; +import Layout from "@theme/Layout"; +import type { ReactElement } from "react"; + +import { homepageContent } from "./_homepage"; +import ExternalLinkIcon from "./external-link.svg"; +import styles from "./index.module.css"; +import TopoOverviewDiagram from "../static/img/topo-overview.svg"; + +function joinClasses(...parts: Array): string { + return parts.filter(Boolean).join(" "); +} + +export default function Home(): ReactElement { + return ( + +
+
+
+

{homepageContent.headline}

+

{homepageContent.lead}

+
+ {homepageContent.heroLinks.map((link) => ( + + {link.label} + {link.external && ( +
+
+
+ +
+
+ +
+ {homepageContent.bottomCards.map((card) => ( + +
+

{card.label}

+

{card.title}

+

{card.description}

+
+ + {card.cta} + + + ))} +
+ +
+
+

+ {homepageContent.codeExamples.eyebrow} +

+

{homepageContent.codeExamples.title}

+

{homepageContent.codeExamples.subtitle}

+
+
+ {homepageContent.codeExamples.items.map((example) => ( +
+
+ {example.label} +

{example.title}

+

{example.description}

+
+
+                  {example.code}
+                
+
+ ))} +
+
+
+
+ ); +} diff --git a/docs/introduction/img/topo-overview.svg b/docs/static/img/topo-overview.svg similarity index 68% rename from docs/introduction/img/topo-overview.svg rename to docs/static/img/topo-overview.svg index 3e7e10ae..77f84f0b 100644 --- a/docs/introduction/img/topo-overview.svg +++ b/docs/static/img/topo-overview.svg @@ -6,32 +6,32 @@ - + - - Host - Development machine + + Host + Development machine Topo Project Compose services x-topo parameters - + Topo Configure · build · deploy - - Deploy - over SSH + + Deploy + over SSH - - Target - Arm device + + Target + Arm device Linux containers @@ -40,17 +40,17 @@ Remoteproc Runtime Firmware on remote processors - + Review on target Check the running services - + Tweak the project Edit code or run topo configure - +