diff options
| author | Dax <[email protected]> | 2025-10-01 19:38:15 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-10-01 19:38:15 -0400 |
| commit | a782e3dac2c60429c2f06ccb1b20edaf5797ca0f (patch) | |
| tree | bee5e0104d9e5721d8d48df899c45a292cfb6889 /packages/console/app/src/component | |
| parent | 70da3a9399d3385b53f7831beb08f716b972860d (diff) | |
| download | opencode-a782e3dac2c60429c2f06ccb1b20edaf5797ca0f.tar.gz opencode-a782e3dac2c60429c2f06ccb1b20edaf5797ca0f.zip | |
Zen lander (#2907)
Co-authored-by: David Hill <[email protected]>
Co-authored-by: GitHub Action <[email protected]>
Co-authored-by: Adam <[email protected]>
Co-authored-by: Jay V <[email protected]>
Diffstat (limited to 'packages/console/app/src/component')
| -rw-r--r-- | packages/console/app/src/component/email-signup.tsx | 49 | ||||
| -rw-r--r-- | packages/console/app/src/component/faq.tsx | 33 | ||||
| -rw-r--r-- | packages/console/app/src/component/footer.tsx | 34 | ||||
| -rw-r--r-- | packages/console/app/src/component/header.tsx | 127 | ||||
| -rw-r--r-- | packages/console/app/src/component/icon.tsx | 33 | ||||
| -rw-r--r-- | packages/console/app/src/component/legal.tsx | 9 |
6 files changed, 260 insertions, 25 deletions
diff --git a/packages/console/app/src/component/email-signup.tsx b/packages/console/app/src/component/email-signup.tsx new file mode 100644 index 000000000..fec516a5f --- /dev/null +++ b/packages/console/app/src/component/email-signup.tsx @@ -0,0 +1,49 @@ +import { action, useSubmission } from "@solidjs/router" +import dock from "../asset/lander/dock.png" +import { Resource } from "sst" +import { Show } from "solid-js" + +const emailSignup = action(async (formData: FormData) => { + "use server" + const emailAddress = formData.get("email")! + const listId = "8b9bb82c-9d5f-11f0-975f-0df6fd1e4945" + const response = await fetch(`https://api.emailoctopus.com/lists/${listId}/contacts`, { + method: "PUT", + headers: { + Authorization: `Bearer ${Resource.EMAILOCTOPUS_API_KEY.value}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email_address: emailAddress, + }), + }) + console.log(response) + return true +}) + +export function EmailSignup() { + const submission = useSubmission(emailSignup) + return ( + <section data-component="email"> + <div data-slot="dock"> + <img src={dock} alt="" /> + </div> + <div data-slot="section-title"> + <h3>OpenCode will be available on desktop soon</h3> + <p>Join the waitlist for early access.</p> + </div> + <form data-slot="form" action={emailSignup} method="post"> + <input type="email" name="email" placeholder="Email address" required /> + <button type="submit" disabled={submission.pending}> + Subscribe + </button> + </form> + <Show when={submission.result}> + <div style="color: #03B000; margin-top: 24px;">Almost done, check your inbox and confirm your email address</div> + </Show> + <Show when={submission.error}> + <div style="color: #FF408F; margin-top: 24px;">{submission.error}</div> + </Show> + </section> + ) +} diff --git a/packages/console/app/src/component/faq.tsx b/packages/console/app/src/component/faq.tsx new file mode 100644 index 000000000..2b28fc0fe --- /dev/null +++ b/packages/console/app/src/component/faq.tsx @@ -0,0 +1,33 @@ +import { Collapsible } from "@kobalte/core/collapsible" +import { ParentProps } from "solid-js" + +export function Faq(props: ParentProps & { question: string }) { + return ( + <Collapsible data-slot="faq-item"> + <Collapsible.Trigger data-slot="faq-question"> + <svg + data-slot="faq-icon-plus" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path d="M12.5 11.5H19V12.5H12.5V19H11.5V12.5H5V11.5H11.5V5H12.5V11.5Z" fill="#6D717D" /> + </svg> + <svg + data-slot="faq-icon-minus" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + xmlns="http://www.w3.org/2000/svg" + > + <path d="M5 11.5H19V12.5H5Z" fill="#6D717D" /> + </svg> + <div data-slot="faq-question-text">{props.question}</div> + </Collapsible.Trigger> + <Collapsible.Content data-slot="faq-answer">{props.children}</Collapsible.Content> + </Collapsible> + ) +} diff --git a/packages/console/app/src/component/footer.tsx b/packages/console/app/src/component/footer.tsx new file mode 100644 index 000000000..f4ff846db --- /dev/null +++ b/packages/console/app/src/component/footer.tsx @@ -0,0 +1,34 @@ +import { A, createAsync } from "@solidjs/router" +import { createMemo } from "solid-js" +import { github } from "~/lib/github" + +export function Footer() { + const githubData = createAsync(() => github()) + const starCount = createMemo(() => + githubData()?.stars + ? new Intl.NumberFormat("en-US", { + notation: "compact", + compactDisplay: "short", + }).format(githubData()!.stars!) + : "25K", + ) + + return ( + <footer data-component="footer"> + <div data-slot="cell"> + <A href="https://github.com/sst/opencode" target="_blank"> + GitHub <span>[{starCount()}]</span> + </A> + </div> + <div data-slot="cell"> + <A href="/docs">Docs</A> + </div> + <div data-slot="cell"> + <A href="https://opencode.ai/discord">Discord</A> + </div> + <div data-slot="cell"> + <A href="https://x/opencode">X</A> + </div> + </footer> + ) +} diff --git a/packages/console/app/src/component/header.tsx b/packages/console/app/src/component/header.tsx new file mode 100644 index 000000000..c5447d1c1 --- /dev/null +++ b/packages/console/app/src/component/header.tsx @@ -0,0 +1,127 @@ +import logoLight from "../asset/logo-ornate-light.svg" +import logoDark from "../asset/logo-ornate-dark.svg" +import { A, createAsync } from "@solidjs/router" +import { createMemo, Match, Show, Switch } from "solid-js" +import { createStore } from "solid-js/store" +import { github } from "~/lib/github" + +export function Header(props: { zen?: boolean }) { + const githubData = createAsync(() => github()) + const starCount = createMemo(() => + githubData()?.stars + ? new Intl.NumberFormat("en-US", { + notation: "compact", + compactDisplay: "short", + }).format(githubData()?.stars!) + : "25K", + ) + + const [store, setStore] = createStore({ + mobileMenuOpen: false, + }) + + return ( + <section data-component="top"> + <A href="/"> + <img data-slot="logo light" src={logoLight} alt="opencode logo light" /> + <img data-slot="logo dark" src={logoDark} alt="opencode logo dark" /> + </A> + <nav data-component="nav-desktop"> + <ul> + <li> + <A href="https://github.com/sst/opencode" target="_blank"> + GitHub <span>[{starCount()}]</span> + </A> + </li> + <li> + <A href="/docs">Docs</A> + </li> + <li> + <Switch> + <Match when={props.zen}> + <A href="/auth">Login</A> + </Match> + <Match when={!props.zen}> + <A href="/zen">Zen</A> + </Match> + </Switch> + </li> + </ul> + </nav> + <nav data-component="nav-mobile"> + <button + type="button" + data-component="nav-mobile-toggle" + aria-expanded="false" + aria-controls="nav-mobile-menu" + class="nav-toggle" + onClick={() => setStore("mobileMenuOpen", !store.mobileMenuOpen)} + > + <span class="sr-only">Open menu</span> + <Switch> + <Match when={store.mobileMenuOpen}> + <svg + class="icon icon-close" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + aria-hidden="true" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M12.7071 11.9993L18.0104 17.3026L17.3033 18.0097L12 12.7064L6.6967 18.0097L5.98959 17.3026L11.2929 11.9993L5.98959 6.69595L6.6967 5.98885L12 11.2921L17.3033 5.98885L18.0104 6.69595L12.7071 11.9993Z" + fill="currentColor" + /> + </svg> + </Match> + <Match when={!store.mobileMenuOpen}> + <svg + class="icon icon-hamburger" + width="24" + height="24" + viewBox="0 0 24 24" + fill="none" + aria-hidden="true" + xmlns="http://www.w3.org/2000/svg" + > + <path d="M19 17H5V16H19V17Z" fill="currentColor" /> + <path d="M19 8H5V7H19V8Z" fill="currentColor" /> + </svg> + </Match> + </Switch> + </button> + + <Show when={store.mobileMenuOpen}> + <div id="nav-mobile-menu" data-component="nav-mobile"> + <nav data-component="nav-mobile-menu-list"> + <ul> + <li> + <A href="/">Home</A> + </li> + <li> + <A href="https://github.com/sst/opencode" target="_blank"> + GitHub <span>[{starCount()}]</span> + </A> + </li> + <li> + <A href="/docs">Docs</A> + </li> + <li> + <Switch> + <Match when={props.zen}> + <A href="/auth">Login</A> + </Match> + <Match when={!props.zen}> + <A href="/zen">Zen</A> + </Match> + </Switch> + </li> + </ul> + </nav> + </div> + </Show> + </nav> + </section> + ) +} diff --git a/packages/console/app/src/component/icon.tsx b/packages/console/app/src/component/icon.tsx index a82572e62..fa28316e8 100644 --- a/packages/console/app/src/component/icon.tsx +++ b/packages/console/app/src/component/icon.tsx @@ -34,38 +34,21 @@ export function IconLogo(props: JSX.SvgSVGAttributes<SVGSVGElement>) { export function IconCopy(props: JSX.SvgSVGAttributes<SVGSVGElement>) { return ( - <svg {...props} viewBox="0 0 512 512"> - <rect - width="336" - height="336" - x="128" - y="128" - fill="none" - stroke="currentColor" - stroke-linejoin="round" - stroke-width="32" - rx="57" - ry="57" - ></rect> + <svg {...props} width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path - fill="none" - stroke="currentColor" - stroke-linecap="round" - stroke-linejoin="round" - stroke-width="32" - d="m383.5 128l.5-24a56.16 56.16 0 0 0-56-56H112a64.19 64.19 0 0 0-64 64v216a56.16 56.16 0 0 0 56 56h24" - ></path> + d="M8.75 8.75V2.75H21.25V15.25H15.25M15.25 8.75H2.75V21.25H15.25V8.75Z" + stroke="#8E8B8B" + stroke-width="1.5" + stroke-linecap="square" + /> </svg> ) } export function IconCheck(props: JSX.SvgSVGAttributes<SVGSVGElement>) { return ( - <svg {...props} viewBox="0 0 24 24"> - <path - fill="currentColor" - d="M9 16.17L5.53 12.7a.996.996 0 1 0-1.41 1.41l4.18 4.18c.39.39 1.02.39 1.41 0L20.29 7.71a.996.996 0 1 0-1.41-1.41z" - ></path> + <svg {...props} width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M2.75 15.0938L9 20.25L21.25 3.75" stroke="#03B000" stroke-width="2" stroke-linecap="square" /> </svg> ) } diff --git a/packages/console/app/src/component/legal.tsx b/packages/console/app/src/component/legal.tsx new file mode 100644 index 000000000..d692e4622 --- /dev/null +++ b/packages/console/app/src/component/legal.tsx @@ -0,0 +1,9 @@ +export function Legal() { + return ( + <div data-component="legal"> + <span> + ©{new Date().getFullYear()} <a href="https://anoma.ly">Anomaly</a> + </span> + </div> + ) +} |
