diff --git a/cloud/app/src/routes/workspace.css b/cloud/app/src/routes/workspace.css index 2658ad7e..ed94365f 100644 --- a/cloud/app/src/routes/workspace.css +++ b/cloud/app/src/routes/workspace.css @@ -15,7 +15,7 @@ cursor: pointer; transition: all 0.15s ease; - &:hover { + &:hover:not(:disabled) { background-color: var(--color-surface-hover); border-color: var(--color-accent); } @@ -26,13 +26,7 @@ &:disabled { opacity: 0.5; - cursor: not-allowed; - - &:hover { - background-color: var(--color-bg); - border-color: var(--color-border); - transform: none; - } + transform: none; } &[data-color="primary"] { @@ -40,7 +34,7 @@ border-color: var(--color-primary); color: var(--color-primary-text); - &:hover { + &:hover:not(:disabled) { background-color: var(--color-primary-hover); border-color: var(--color-primary-hover); } @@ -51,7 +45,7 @@ border-color: transparent; color: var(--color-text-muted); - &:hover { + &:hover:not(:disabled) { background-color: var(--color-surface-hover); border-color: var(--color-border); color: var(--color-text); diff --git a/cloud/app/src/routes/workspace/[id].css b/cloud/app/src/routes/workspace/[id].css index 397ceec5..2d9b0e63 100644 --- a/cloud/app/src/routes/workspace/[id].css +++ b/cloud/app/src/routes/workspace/[id].css @@ -47,12 +47,6 @@ font-size: var(--font-size-md); } } - - p { - line-height: 1.4; - font-size: var(--font-size-sm); - color: var(--color-text-muted); - } } } section:not(:last-child) { @@ -192,11 +186,35 @@ &[data-slot="key-value"] { font-family: var(--font-mono); - div { - cursor: pointer; + button { display: flex; align-items: center; gap: var(--space-2); + padding: var(--space-2) var(--space-3); + font-size: var(--font-size-sm); + font-weight: 400; + border: none; + background-color: transparent; + color: var(--color-text-muted); + font-family: var(--font-mono); + border-radius: var(--border-radius-sm); + cursor: pointer; + transition: all 0.15s ease; + text-transform: none; + + &:hover:not(:disabled) { + background-color: var(--color-bg-surface); + color: var(--color-text); + } + + &:disabled { + cursor: default; + color: var(--color-text); + } + + span { + font-family: inherit; + } } } @@ -262,6 +280,9 @@ [data-slot="value"] { color: var(--color-danger); } + [data-slot="currency"] { + color: var(--color-danger); + } } [data-slot="currency"] { @@ -428,4 +449,186 @@ } } } + + [data-slot="new-user-sections"] { + display: flex; + flex-direction: column; + gap: var(--space-16); + + @media (max-width: 30rem) { + gap: var(--space-8); + } + + [data-component="feature-grid"] { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: var(--space-6); + + @media (max-width: 30rem) { + grid-template-columns: 1fr; + gap: var(--space-4); + } + + [data-slot="feature"] { + display: flex; + flex-direction: column; + gap: var(--space-2); + padding: var(--space-4); + border: 1px solid var(--color-border); + border-radius: var(--border-radius-sm); + background-color: var(--color-bg-surface); + + h3 { + font-size: var(--font-size-sm); + font-weight: 600; + margin: 0; + color: var(--color-text); + text-transform: uppercase; + letter-spacing: -0.025rem; + } + + p { + font-size: var(--font-size-sm); + line-height: 1.5; + margin: 0; + color: var(--color-text-muted); + } + } + } + + [data-component="api-key-highlight"] { + display: flex; + flex-direction: column; + gap: var(--space-6); + + [data-slot="section-title"] { + display: flex; + flex-direction: column; + gap: var(--space-1); + + h2 { + font-size: var(--font-size-md); + font-weight: 600; + line-height: 1.2; + letter-spacing: -0.03125rem; + margin: 0; + color: var(--color-text-secondary); + text-transform: uppercase; + + @media (max-width: 30rem) { + font-size: var(--font-size-md); + } + } + } + + [data-slot="key-display"] { + display: flex; + flex-direction: column; + gap: var(--space-3); + + [data-slot="key-container"] { + display: flex; + gap: var(--space-3); + padding: var(--space-4); + border: 2px solid var(--color-accent); + border-radius: var(--border-radius-sm); + background-color: var(--color-bg-surface); + align-items: center; + + @media (max-width: 40rem) { + flex-direction: column; + gap: var(--space-3); + align-items: stretch; + } + + [data-slot="key-value"] { + flex: 1; + font-family: var(--font-mono); + font-size: var(--font-size-sm); + color: var(--color-text); + background-color: var(--color-bg); + padding: var(--space-3); + border-radius: var(--border-radius-sm); + border: 1px solid var(--color-border); + word-break: break-all; + line-height: 1.4; + + @media (max-width: 40rem) { + font-size: var(--font-size-xs); + padding: var(--space-2-5); + } + } + + button { + display: flex; + align-items: center; + gap: var(--space-2); + padding: var(--space-3) var(--space-4); + font-size: var(--font-size-sm); + font-weight: 500; + white-space: nowrap; + min-width: 130px; + + @media (max-width: 40rem) { + justify-content: center; + padding: var(--space-2-5) var(--space-3); + font-size: var(--font-size-xs); + min-width: 96px; + } + } + } + } + } + + [data-component="next-steps"] { + display: flex; + flex-direction: column; + gap: var(--space-6); + + [data-slot="section-title"] { + display: flex; + flex-direction: column; + gap: var(--space-1); + + h2 { + font-size: var(--font-size-md); + font-weight: 600; + line-height: 1.2; + letter-spacing: -0.03125rem; + margin: 0; + color: var(--color-text-secondary); + text-transform: uppercase; + + @media (max-width: 30rem) { + font-size: var(--font-size-md); + } + } + } + + ol { + margin: 0; + padding-left: 0; + display: flex; + flex-direction: column; + gap: var(--space-2); + list-style-position: inside; + + li { + font-size: var(--font-size-sm); + line-height: 1.5; + color: var(--color-text-muted); + + code { + font-family: var(--font-mono); + font-size: var(--font-size-xs); + padding: var(--space-1) var(--space-2); + background-color: var(--color-bg-surface); + border: 1px solid var(--color-border); + border-radius: var(--border-radius-sm); + color: var(--color-text); + } + } + } + } + } } diff --git a/cloud/app/src/routes/workspace/[id].tsx b/cloud/app/src/routes/workspace/[id].tsx index 959799c6..19d711e8 100644 --- a/cloud/app/src/routes/workspace/[id].tsx +++ b/cloud/app/src/routes/workspace/[id].tsx @@ -237,7 +237,12 @@ function KeysSection() { {key.name} -
copyKeyToClipboard(key.key, key.id)} title="Click to copy API key"> +
+ {formatDateForTable(key.timeCreated)} @@ -464,7 +469,99 @@ function PaymentsSection() { ) } -export default function () { +function NewUserSection() { + const params = useParams() + const keys = createAsync(() => listKeys(params.id)) + const [copiedKey, setCopiedKey] = createSignal(false) + + async function copyKeyToClipboard(text: string) { + try { + await navigator.clipboard.writeText(text) + setCopiedKey(true) + setTimeout(() => setCopiedKey(false), 2000) + } catch (error) { + console.error("Failed to copy to clipboard:", error) + } + } + + return ( +
+
+
+

Tested & Verified Models

+

We've benchmarked and tested models specifically for coding agents to ensure the best performance.

+
+
+

Highest Quality

+

Access models configured for optimal performance - no downgrades or routing to cheaper providers.

+
+
+

No Lock-in

+

Use Zen with any coding agent, and continue using other providers with opencode whenever you want.

+
+
+ +
+
+

Your API Key

+
+ + +
+
+ {keys()![0].key} + +
+
+
+
+ +
+
+

Next Steps

+
+
    +
  1. Copy your API key above
  2. +
  3. + Run opencode auth login and select opencode +
  4. +
  5. Paste your API key when prompted
  6. +
  7. + Run /models to see available models +
  8. +
+
+
+ ) +} + +export default function() { + const params = useParams() + const keys = createAsync(() => listKeys(params.id)) + const usage = createAsync(() => getUsageInfo(params.id)) + + const isNewUser = createMemo(() => { + const keysList = keys() + const usageList = usage() + return keysList?.length === 1 && (!usageList || usageList.length === 0) + }) + return (
@@ -478,12 +575,14 @@ export default function () {

-
- - - - -
+ }> +
+ + + + +
+
) } diff --git a/packages/web/src/content/docs/index.mdx b/packages/web/src/content/docs/index.mdx index 7513d5bf..928f89c3 100644 --- a/packages/web/src/content/docs/index.mdx +++ b/packages/web/src/content/docs/index.mdx @@ -79,7 +79,7 @@ $ opencode auth login ┌ Add credential │ ◆ Select provider -│ ● Anthropic (recommended) +│ ● Anthropic │ ○ OpenAI │ ○ Google │ ○ Amazon Bedrock diff --git a/packages/web/src/content/docs/providers.mdx b/packages/web/src/content/docs/providers.mdx index 641ed7ce..7b109265 100644 --- a/packages/web/src/content/docs/providers.mdx +++ b/packages/web/src/content/docs/providers.mdx @@ -58,7 +58,7 @@ If you are new, we recommend starting with opencode zen. ::: 1. You sign in to **opencode zen** and get your API key. -2. You run `opencode auth login` and select opencode zen and add your API key. +2. You run `opencode auth login` and select opencode and add your API key. 3. Run `/models` in the TUI to see the list of models we recommend. It works like any other provider in opencode. And is completely optional to use @@ -131,9 +131,7 @@ $ opencode auth login ┌ Add credential │ ◆ Select provider -│ ● Anthropic (recommended) -│ ○ OpenAI -│ ○ Google +│ ● Anthropic │ ... └ ``` diff --git a/packages/web/src/content/docs/zen.mdx b/packages/web/src/content/docs/zen.mdx index 3f54d30e..140c66be 100644 --- a/packages/web/src/content/docs/zen.mdx +++ b/packages/web/src/content/docs/zen.mdx @@ -50,7 +50,7 @@ opencode zen is an AI gateway that gives you access to these models. opencode zen works like any other provider in opencode. 1. You sign in to **opencode zen** and get your API key. -2. You run `opencode auth login` and select opencode zen and add your API key. +2. You run `opencode auth login` and select opencode and add your API key. 3. Run `/models` in the TUI to see the list of models we recommend. You are charged per request and you can add credits to your account.