diff options
| author | Dax Raad <[email protected]> | 2025-08-15 19:29:24 -0400 |
|---|---|---|
| committer | Dax Raad <[email protected]> | 2025-08-15 19:29:42 -0400 |
| commit | 07cf8847fb1908ff5dc47a771f57d23926baa1ce (patch) | |
| tree | aef73a8ac42e755404cb56107137a7fc4eff3ffd /cloud/app/src/routes | |
| parent | 650e67f1dfd4790152c70864da6c1ade4884ab58 (diff) | |
| download | opencode-07cf8847fb1908ff5dc47a771f57d23926baa1ce.tar.gz opencode-07cf8847fb1908ff5dc47a771f57d23926baa1ce.zip | |
wip: cloud stuff
Diffstat (limited to 'cloud/app/src/routes')
| -rw-r--r-- | cloud/app/src/routes/[...404].tsx | 19 | ||||
| -rw-r--r-- | cloud/app/src/routes/index.css | 264 | ||||
| -rw-r--r-- | cloud/app/src/routes/index.tsx | 169 |
3 files changed, 452 insertions, 0 deletions
diff --git a/cloud/app/src/routes/[...404].tsx b/cloud/app/src/routes/[...404].tsx new file mode 100644 index 000000000..4ea71ec7f --- /dev/null +++ b/cloud/app/src/routes/[...404].tsx @@ -0,0 +1,19 @@ +import { Title } from "@solidjs/meta"; +import { HttpStatusCode } from "@solidjs/start"; + +export default function NotFound() { + return ( + <main> + <Title>Not Found</Title> + <HttpStatusCode code={404} /> + <h1>Page Not Found</h1> + <p> + Visit{" "} + <a href="https://start.solidjs.com" target="_blank"> + start.solidjs.com + </a>{" "} + to learn how to build SolidStart apps. + </p> + </main> + ); +} diff --git a/cloud/app/src/routes/index.css b/cloud/app/src/routes/index.css new file mode 100644 index 000000000..e3b11c605 --- /dev/null +++ b/cloud/app/src/routes/index.css @@ -0,0 +1,264 @@ +[data-page="home"] { + --color-bg: oklch(0.2097 0.008 274.53); + --color-border: oklch(0.46 0.02 269.88); + --color-text: #ffffff; + --color-text-secondary: oklch(0.72 0.01 270.15); + --color-text-dimmed: hsl(224, 7%, 46%); + padding: var(--space-6); + font-family: var(--font-mono); + color: var(--color-text); + + a { + color: var(--color-text); + text-decoration: underline; + text-underline-offset: 0.1875rem; + } + + background: var(--color-bg); + position: fixed; + overflow-y: scroll; + inset: 0; + + [data-component="content"] { + max-width: 67.5rem; + margin: 0 auto; + border: 2px solid var(--color-border); + } + + [data-component="top"] { + padding: var(--space-12); + display: flex; + flex-direction: column; + align-items: start; + gap: var(--space-4); + + [data-slot="logo"] { + height: 70px; + } + + [data-slot="title"] { + font-size: var(--font-size-2xl); + text-transform: uppercase; + } + } + + [data-component="cta"] { + height: var(--space-19); + border-top: 2px solid var(--color-border); + display: flex; + + [data-slot="left"] { + display: flex; + padding: 0 var(--space-12); + text-transform: uppercase; + text-decoration: underline; + align-items: center; + justify-content: center; + text-underline-offset: 0.1875rem; + border-right: 2px solid var(--color-border); + + a { + color: var(--color-text); + text-decoration: underline; + } + } + + [data-slot="right"] { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: 0.625rem; + padding: 0 var(--space-6); + } + + [data-slot="command"] { + all: unset; + display: flex; + align-items: center; + cursor: pointer; + color: var(--color-text-secondary); + font-size: 1.125rem; + font-family: var(--font-mono); + gap: var(--space-2); + } + + [data-slot="highlight"] { + color: var(--color-text); + font-weight: 500; + } + } + + [data-component="features"] { + border-top: 2px solid var(--color-border); + padding: var(--space-12); + + [data-slot="list"] { + padding-left: var(--space-4); + margin: 0; + list-style: disc; + + li { + margin-bottom: var(--space-4); + + strong { + text-transform: uppercase; + font-weight: 600; + } + } + + li:last-child { + margin-bottom: 0; + } + } + } + + [data-component="install"] { + border-top: 2px solid var(--color-border); + display: grid; + grid-template-columns: 1fr 1fr; + grid-template-rows: 1fr 1fr; + + @media (max-width: 40rem) { + grid-template-columns: 1fr; + grid-template-rows: auto; + } + } + + [data-component="title"] { + letter-spacing: -0.03125rem; + text-transform: uppercase; + font-weight: 400; + font-size: var(--font-size-md); + flex-shrink: 0; + color: oklch(0.55 0.02 269.87); + } + + [data-component="method"] { + padding: var(--space-4) var(--space-6); + display: flex; + flex-direction: column; + align-items: start; + gap: var(--space-3); + + &:nth-child(1) {} + + &:nth-child(2) { + border-left: 2px solid var(--color-border); + } + + &:nth-child(3) { + border-top: 2px solid var(--color-border); + } + + &:nth-child(4) { + border-top: 2px solid var(--color-border); + border-left: 2px solid var(--color-border); + } + + [data-slot="button"] { + all: unset; + cursor: pointer; + display: flex; + align-items: center; + color: var(--color-text-secondary); + gap: var(--space-2); + + strong { + color: var(--color-text); + font-weight: 500; + } + } + } + + [data-component="screenshots"] { + border-top: 2px solid var(--color-border); + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0; + + [data-slot="left"] { + padding: var(--space-8) var(--space-6); + display: flex; + flex-direction: column; + + img { + width: 100%; + height: "auto"; + } + } + + [data-slot="right"] { + display: grid; + grid-template-rows: 1fr 1fr; + border-left: 2px solid var(--color-border); + } + + [data-slot="filler"] { + display: flex; + flex-grow: 1; + align-items: center; + justify-content: center; + } + + [data-slot="cell"] { + padding: var(--space-8) var(--space-6); + display: flex; + flex-direction: column; + gap: var(--space-4); + + &:nth-child(2) { + border-top: 2px solid var(--color-border); + } + + img { + width: 80%; + height: "auto"; + } + } + } + + [data-component="copy-status"] { + [data-slot="copy"] { + display: block; + width: 16px; + height: 16px; + color: var(--color-text-dimmed); + + [data-copied] & { + display: none; + } + } + + [data-slot="check"] { + display: none; + width: 16px; + height: 16px; + color: white; + + [data-copied] & { + display: block; + } + } + } + + [data-component="footer"] { + border-top: 2px solid var(--color-border); + display: grid; + grid-template-columns: 1fr 1fr 1fr; + font-size: var(--font-size-lg); + height: var(--space-20); + + [data-slot="cell"] { + display: flex; + align-items: center; + justify-content: center; + border-right: 2px solid var(--color-border); + text-transform: uppercase; + + &:last-child { + border-right: none; + } + } + } +} diff --git a/cloud/app/src/routes/index.tsx b/cloud/app/src/routes/index.tsx new file mode 100644 index 000000000..90062d0b5 --- /dev/null +++ b/cloud/app/src/routes/index.tsx @@ -0,0 +1,169 @@ +import { Title } from "@solidjs/meta" +import { onCleanup, onMount } from "solid-js" +import "./index.css" +import logo from "../asset/logo-ornate-dark.svg" +import IMG_SPLASH from "../asset/screenshot-splash.webp" +import IMG_VSCODE from "../asset/screenshot-vscode.webp" +import IMG_GITHUB from "../asset/screenshot-github.webp" +import { IconCopy, IconCheck } from "../component/icon" + +function CopyStatus() { + return ( + <div data-component="copy-status"> + <IconCopy data-slot="copy" /> + <IconCheck data-slot="check" /> + </div> + ) +} + +export default function Home() { + onMount(() => { + const commands = document.querySelectorAll("[data-copy]") + for (const button of commands) { + const callback = () => { + const text = button.textContent + alert(text) + if (text) { + navigator.clipboard.writeText(text) + button.setAttribute("data-copied", "") + setTimeout(() => { + button.removeAttribute("data-copied") + }, 1500) + } + } + button.addEventListener("click", callback) + onCleanup(() => { + button.removeEventListener("click", callback) + }) + } + }) + + return ( + <main data-page="home"> + <Title>opencode | AI coding agent built for the terminal</Title> + <div data-component="content"> + <section data-component="top"> + <img data-slot="logo" src={logo} alt="logo" /> + <h1 data-slot="title">The AI coding agent built for the terminal.</h1> + </section> + + <section data-component="cta"> + <div data-slot="left"> + <a href="/docs">Get Started</a> + </div> + <div data-slot="right"> + <button data-copy data-slot="command" data-command="curl -fsSL https://opencode.ai/install | bash"> + <span> + <span>curl -fsSL </span> + <span data-slot="protocol">https://</span> + <span data-slot="highlight">opencode.ai/install</span> + | bash + </span> + <CopyStatus /> + </button> + </div> + </section> + + <section data-component="features"> + <ul data-slot="list"> + <li> + <strong>Native TUI</strong>: A responsive, native, themeable terminal UI. + </li> + <li> + <strong>LSP enabled</strong>: Automatically loads the right LSPs for the LLM. + </li> + <li> + <strong>Multi-session</strong>: Start multiple agents in parallel on the same project. + </li> + <li> + <strong>Shareable links</strong>: Share a link to any sessions for reference or to debug. + </li> + <li> + <strong>Claude Pro</strong>: Log in with Anthropic to use your Claude Pro or Max account. + </li> + <li> + <strong>Use any model</strong>: Supports 75+ LLM providers through{" "} + <a href="https://models.dev">Models.dev</a>, including local models. + </li> + </ul> + </section> + + <section data-component="install"> + <div data-component="method"> + <h3 data-component="title">npm</h3> + <button data-copy data-slot="button"> + <span> + npm install -g <strong>opencode-ai</strong> + </span> + <CopyStatus /> + </button> + </div> + <div data-component="method"> + <h3 data-component="title">bun</h3> + <button data-copy data-slot="button"> + <span> + bun install -g <strong>opencode-ai</strong> + </span> + <CopyStatus /> + </button> + </div> + <div data-component="method"> + <h3 data-component="title">homebrew</h3> + <button data-copy data-slot="button"> + <span> + brew install <strong>sst/tap/opencode</strong> + </span> + <CopyStatus /> + </button> + </div> + <div data-component="method"> + <h3 data-component="title">paru</h3> + <button data-copy data-slot="button"> + <span> + paru -S <strong>opencode-bin</strong> + </span> + <CopyStatus /> + </button> + </div> + </section> + + <section data-component="screenshots"> + <div data-slot="left"> + <div data-component="title">opencode TUI with tokyonight theme</div> + <div data-slot="filler"> + <img src={IMG_SPLASH} alt="opencode TUI with tokyonight theme" /> + </div> + </div> + <div data-slot="right"> + <div data-slot="cell"> + <div data-component="title">opencode in VS Code</div> + <div data-slot="filler"> + <img src={IMG_VSCODE} alt="opencode in VS Code" /> + </div> + </div> + <div data-slot="cell"> + <div data-component="title">opencode in GitHub</div> + <div data-slot="filler"> + <img src={IMG_GITHUB} alt="opencode in GitHub" /> + </div> + </div> + </div> + </section> + + <footer data-component="footer"> + <div data-slot="cell"> + <a href="https://github.com/sst/opencode">GitHub</a> + </div> + <div data-slot="cell"> + <a href="https://opencode.ai/discord">Discord</a> + </div> + <div data-slot="cell"> + <span> + ©2025 <a href="https://anoma.ly">Anomaly Innovations</a> + </span> + </div> + </footer> + </div> + </main> + ) +} |
