summaryrefslogtreecommitdiffhomepage
path: root/packages/console/app/src/routes/black
diff options
context:
space:
mode:
authorAaron Iker <[email protected]>2026-01-15 21:31:50 +0100
committerGitHub <[email protected]>2026-01-15 21:31:50 +0100
commitfe58c649cb83c73c3f2c3094682189ffa78ccc4f (patch)
tree660898bc090b38ddff5faccdf0c9598aa0db9726 /packages/console/app/src/routes/black
parentaf2a09940c5b411c27f72c039a0351a3c19efd02 (diff)
downloadopencode-fe58c649cb83c73c3f2c3094682189ffa78ccc4f.tar.gz
opencode-fe58c649cb83c73c3f2c3094682189ffa78ccc4f.zip
feat(console): Update /black plan selection, light rays effect. mobile styles (#8731)
Co-authored-by: Github Action <[email protected]>
Diffstat (limited to 'packages/console/app/src/routes/black')
-rw-r--r--packages/console/app/src/routes/black/index.tsx227
1 files changed, 128 insertions, 99 deletions
diff --git a/packages/console/app/src/routes/black/index.tsx b/packages/console/app/src/routes/black/index.tsx
index c46fdc0da..8f7ee95f3 100644
--- a/packages/console/app/src/routes/black/index.tsx
+++ b/packages/console/app/src/routes/black/index.tsx
@@ -1,12 +1,13 @@
import { A, useSearchParams } from "@solidjs/router"
import { Title } from "@solidjs/meta"
-import { createMemo, createSignal, For, onMount, Show } from "solid-js"
+import { createMemo, createSignal, For, Match, onMount, Show, Switch } from "solid-js"
import { PlanIcon, plans } from "./common"
export default function Black() {
const [params] = useSearchParams()
const [selected, setSelected] = createSignal<string | null>((params.plan as string) || null)
const [mounted, setMounted] = createSignal(false)
+ const selectedPlan = createMemo(() => plans.find((p) => p.id === selected()))
onMount(() => {
requestAnimationFrame(() => setMounted(true))
@@ -37,110 +38,138 @@ export default function Black() {
<>
<Title>opencode</Title>
<section data-slot="cta">
- <div data-slot="pricing">
- <For each={plans}>
- {(plan) => {
- const isSelected = createMemo(() => selected() === plan.id)
- const isCollapsed = createMemo(() => selected() !== null && selected() !== plan.id)
-
- return (
- <article
- data-slot="pricing-card"
- data-plan-id={plan.id}
- data-selected={isSelected() ? "true" : "false"}
- data-collapsed={isCollapsed() ? "true" : "false"}
- >
+ <Switch>
+ <Match when={!selected()}>
+ <div data-slot="pricing">
+ <For each={plans}>
+ {(plan) => (
<button
type="button"
- data-slot="card-trigger"
onClick={() => select(plan.id)}
- disabled={isSelected()}
+ data-slot="pricing-card"
+ style={{ "view-transition-name": `card-${plan.id}` }}
>
- <div
- data-slot="plan-header"
- style={{
- "view-transition-name": `plan-header-${plan.id}`,
- }}
- >
- <div data-slot="plan-icon">
- <PlanIcon plan={plan.id} />
- </div>
- <p
- data-slot="price"
- style={{
- "view-transition-name": `price-${plan.id}`,
- }}
- >
- <span
- data-slot="amount"
- style={{
- "view-transition-name": `amount-${plan.id}`,
- }}
- >
- ${plan.id}
- </span>
- <Show when={!isSelected()}>
- <span
- data-slot="period"
- style={{
- "view-transition-name": `period-${plan.id}`,
- }}
- >
- per month
- </span>
- </Show>
-
- <Show when={isSelected()}>
- <span
- data-slot="billing"
- style={{
- "view-transition-name": `billing-${plan.id}`,
- }}
- >
- per person billed monthly
- </span>
- </Show>
- {plan.multiplier && (
- <span
- data-slot="multiplier"
- style={{
- "view-transition-name": `multiplier-${plan.id}`,
- }}
- >
- {plan.multiplier}
- </span>
- )}
- </p>
+ <div data-slot="icon" style={{ "view-transition-name": `icon-${plan.id}` }}>
+ <PlanIcon plan={plan.id} />
</div>
+ <p data-slot="price" style={{ "view-transition-name": `price-${plan.id}` }}>
+ <span data-slot="amount">${plan.id}</span> <span data-slot="period">per month</span>
+ <Show when={plan.multiplier}>
+ <span data-slot="multiplier">{plan.multiplier}</span>
+ </Show>
+ </p>
</button>
-
- <Show when={isSelected()}>
- <div data-slot="content">
- <ul data-slot="terms">
- <li>You will be added to the waitlist and activated in batches</li>
- <li>Card won't be charged until subscription is active</li>
- <li>Not unlimited - limits apply and may be adjusted dynamically</li>
- <li>Heavily automated usage will hit limits quickly</li>
- <li>Plans may be discontinued</li>
- <li>Can cancel subscription at anytime</li>
- <li>Cannot issue refunds for consumed subscriptions</li>
- </ul>
- <div data-slot="actions">
- <button type="button" onClick={cancel} data-slot="cancel">
- Cancel
- </button>
- <a href={`/black/subscribe/${plan.id}`} data-slot="continue">
- Continue
- </a>
- </div>
- </div>
- </Show>
- </article>
- )
- }}
- </For>
- </div>
- <p data-slot="fine-print">
+ )}
+ </For>
+ </div>
+ </Match>
+ <Match when={selectedPlan()}>
+ {(plan) => (
+ <div data-slot="selected-plan">
+ <div data-slot="selected-card" style={{ "view-transition-name": `card-${plan().id}` }}>
+ <div data-slot="icon" style={{ "view-transition-name": `icon-${plan().id}` }}>
+ <PlanIcon plan={plan().id} />
+ </div>
+ <p data-slot="price" style={{ "view-transition-name": `price-${plan().id}` }}>
+ <span data-slot="amount">${plan().id}</span>{" "}
+ <span data-slot="period">per person billed monthly</span>
+ <Show when={plan().multiplier}>
+ <span data-slot="multiplier">{plan().multiplier}</span>
+ </Show>
+ </p>
+ <ul data-slot="terms" style={{ "view-transition-name": `terms-${plan().id}` }}>
+ <li>Your subscription will not start immediately</li>
+ <li>You will be added to the waitlist and activated soon</li>
+ <li>Your card will be only charged when your subscription is activated</li>
+ <li>Usage limits apply, heavily automated use may reach limits sooner</li>
+ <li>Subscriptions for individuals, contact Enterprise for teams</li>
+ <li>Limits may be adjusted and plans may be discontinued in the future</li>
+ <li>Cancel your subscription at anytime</li>
+ </ul>
+ <div data-slot="actions" style={{ "view-transition-name": `actions-${plan().id}` }}>
+ <button type="button" onClick={() => cancel()} data-slot="cancel">
+ Cancel
+ </button>
+ <a href={`/black/subscribe/${plan().id}`} data-slot="continue">
+ Continue
+ </a>
+ </div>
+ </div>
+ </div>
+ )}
+ </Match>
+ <Match when={selectedPlan()}>
+ {(plan) => (
+ <div data-slot="selected-plan">
+ <div data-slot="selected-card">
+ <div data-slot="icon" style={{ "view-transition-name": `icon-${plan().id}` }}>
+ <PlanIcon plan={plan().id} />
+ </div>
+ <p data-slot="price" style={{ "view-transition-name": `price-${plan().id}` }}>
+ <span data-slot="amount">${plan().id}</span>{" "}
+ <span data-slot="period">per person billed monthly</span>
+ <Show when={plan().multiplier}>
+ <span data-slot="multiplier">{plan().multiplier}</span>
+ </Show>
+ </p>
+ <ul data-slot="terms" style={{ "view-transition-name": `terms-${plan().id}` }}>
+ <li>Your subscription will not start immediately</li>
+ <li>You will be added to the waitlist and activated soon</li>
+ <li>Your card will be only charged when your subscription is activated</li>
+ <li>Usage limits apply, heavily automated use may reach limits sooner</li>
+ <li>Subscriptions for individuals, contact Enterprise for teams</li>
+ <li>Limits may be adjusted and plans may be discontinued in the future</li>
+ <li>Cancel your subscription at anytime</li>
+ </ul>
+ <div data-slot="actions" style={{ "view-transition-name": `actions-${plan().id}` }}>
+ <button type="button" onClick={() => cancel()} data-slot="cancel">
+ Cancel
+ </button>
+ <a href={`/black/subscribe/${plan().id}`} data-slot="continue">
+ Continue
+ </a>
+ </div>
+ </div>
+ </div>
+ )}
+ </Match>
+ <Match when={selectedPlan()}>
+ {(plan) => (
+ <div data-slot="selected-plan" style={{ "view-transition-name": "selected-plan" }}>
+ <div data-slot="selected-card">
+ <div data-slot="icon">
+ <PlanIcon plan={plan().id} />
+ </div>
+ <p data-slot="price">
+ <span data-slot="amount">${plan().id}</span>{" "}
+ <span data-slot="period">per person billed monthly</span>
+ <Show when={plan().multiplier}>
+ <span data-slot="multiplier">{plan().multiplier}</span>
+ </Show>
+ </p>
+ <ul data-slot="terms" style={{ "view-transition-name": `terms-${plan().id}` }}>
+ <li>Your subscription will not start immediately</li>
+ <li>You will be added to the waitlist and activated soon</li>
+ <li>Your card will be only charged when your subscription is activated</li>
+ <li>Usage limits apply, heavily automated use may reach limits sooner</li>
+ <li>Subscriptions for individuals, contact Enterprise for teams</li>
+ <li>Limits may be adjusted and plans may be discontinued in the future</li>
+ <li>Cancel your subscription at anytime</li>
+ </ul>
+ <div data-slot="actions" style={{ "view-transition-name": `actions-${plan().id}` }}>
+ <button type="button" onClick={() => cancel()} data-slot="cancel">
+ Cancel
+ </button>
+ <a href={`/black/subscribe/${plan().id}`} data-slot="continue">
+ Continue
+ </a>
+ </div>
+ </div>
+ </div>
+ )}
+ </Match>
+ </Switch>
+ <p data-slot="fine-print" style={{ "view-transition-name": "fine-print" }}>
Prices shown don't include applicable tax ยท <A href="/legal/terms-of-service">Terms of Service</A>
</p>
</section>