mirror of
https://github.com/aljazceru/opencode.git
synced 2025-12-24 03:04:21 +01:00
First pass at adding an enterprise page
This commit is contained in:
@@ -36,6 +36,9 @@ export function Header(props: { zen?: boolean }) {
|
|||||||
<li>
|
<li>
|
||||||
<a href="/docs">Docs</a>
|
<a href="/docs">Docs</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<A href="/enterprise">Enterprise</A>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={props.zen}>
|
<Match when={props.zen}>
|
||||||
@@ -107,6 +110,9 @@ export function Header(props: { zen?: boolean }) {
|
|||||||
<li>
|
<li>
|
||||||
<a href="/docs">Docs</a>
|
<a href="/docs">Docs</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<A href="/enterprise">Enterprise</A>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Match when={props.zen}>
|
<Match when={props.zen}>
|
||||||
|
|||||||
52
packages/console/app/src/routes/api/enterprise.ts
Normal file
52
packages/console/app/src/routes/api/enterprise.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import type { APIEvent } from "@solidjs/start/server"
|
||||||
|
import { AWS } from "@opencode-ai/console-core/aws.js"
|
||||||
|
|
||||||
|
interface EnterpriseFormData {
|
||||||
|
name: string
|
||||||
|
company: string
|
||||||
|
role: string
|
||||||
|
email: string
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function POST(event: APIEvent) {
|
||||||
|
try {
|
||||||
|
const body = (await event.request.json()) as EnterpriseFormData
|
||||||
|
|
||||||
|
// Validate required fields
|
||||||
|
if (!body.name || !body.company || !body.role || !body.email || !body.message) {
|
||||||
|
return Response.json({ error: "All fields are required" }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate email format
|
||||||
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
|
||||||
|
if (!emailRegex.test(body.email)) {
|
||||||
|
return Response.json({ error: "Invalid email format" }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create email content
|
||||||
|
const emailContent = `
|
||||||
|
New Enterprise Inquiry
|
||||||
|
|
||||||
|
Name: ${body.name}
|
||||||
|
Company: ${body.company}
|
||||||
|
Role: ${body.role}
|
||||||
|
Email: ${body.email}
|
||||||
|
|
||||||
|
Message:
|
||||||
|
${body.message}
|
||||||
|
`.trim()
|
||||||
|
|
||||||
|
// Send email using AWS SES
|
||||||
|
await AWS.sendEmail({
|
||||||
|
to: "enterprise@opencode.ai",
|
||||||
|
subject: `Enterprise Inquiry from ${body.company}`,
|
||||||
|
body: emailContent,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Response.json({ success: true, message: "Form submitted successfully" }, { status: 200 })
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error processing enterprise form:", error)
|
||||||
|
return Response.json({ error: "Internal server error" }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
552
packages/console/app/src/routes/enterprise/index.css
Normal file
552
packages/console/app/src/routes/enterprise/index.css
Normal file
@@ -0,0 +1,552 @@
|
|||||||
|
::selection {
|
||||||
|
background: var(--color-background-interactive);
|
||||||
|
color: var(--color-text-strong);
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
background: var(--color-background-interactive);
|
||||||
|
color: var(--color-text-inverted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[data-page="enterprise"] {
|
||||||
|
--color-background: hsl(0, 20%, 99%);
|
||||||
|
--color-background-weak: hsl(0, 8%, 97%);
|
||||||
|
--color-background-weak-hover: hsl(0, 8%, 94%);
|
||||||
|
--color-background-strong: hsl(0, 5%, 12%);
|
||||||
|
--color-background-strong-hover: hsl(0, 5%, 18%);
|
||||||
|
--color-background-interactive: hsl(62, 84%, 88%);
|
||||||
|
--color-background-interactive-weaker: hsl(64, 74%, 95%);
|
||||||
|
|
||||||
|
--color-text: hsl(0, 1%, 39%);
|
||||||
|
--color-text-weak: hsl(0, 1%, 60%);
|
||||||
|
--color-text-weaker: hsl(30, 2%, 81%);
|
||||||
|
--color-text-strong: hsl(0, 5%, 12%);
|
||||||
|
--color-text-inverted: hsl(0, 20%, 99%);
|
||||||
|
|
||||||
|
--color-border: hsl(30, 2%, 81%);
|
||||||
|
--color-border-weak: hsl(0, 1%, 85%);
|
||||||
|
|
||||||
|
--color-icon: hsl(0, 1%, 55%);
|
||||||
|
--color-success: hsl(142, 76%, 36%);
|
||||||
|
|
||||||
|
background: var(--color-background);
|
||||||
|
font-family: var(--font-mono);
|
||||||
|
color: var(--color-text);
|
||||||
|
padding-bottom: 5rem;
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
--color-background: hsl(0, 9%, 7%);
|
||||||
|
--color-background-weak: hsl(0, 6%, 10%);
|
||||||
|
--color-background-weak-hover: hsl(0, 6%, 15%);
|
||||||
|
--color-background-strong: hsl(0, 15%, 94%);
|
||||||
|
--color-background-strong-hover: hsl(0, 15%, 97%);
|
||||||
|
--color-background-interactive: hsl(62, 100%, 90%);
|
||||||
|
--color-background-interactive-weaker: hsl(60, 20%, 8%);
|
||||||
|
|
||||||
|
--color-text: hsl(0, 4%, 71%);
|
||||||
|
--color-text-weak: hsl(0, 2%, 49%);
|
||||||
|
--color-text-weaker: hsl(0, 3%, 28%);
|
||||||
|
--color-text-strong: hsl(0, 15%, 94%);
|
||||||
|
--color-text-inverted: hsl(0, 9%, 7%);
|
||||||
|
|
||||||
|
--color-border: hsl(0, 3%, 28%);
|
||||||
|
--color-border-weak: hsl(0, 4%, 23%);
|
||||||
|
|
||||||
|
--color-icon: hsl(10, 3%, 43%);
|
||||||
|
--color-success: hsl(142, 76%, 46%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header and Footer styles - copied from index.css */
|
||||||
|
[data-component="top"] {
|
||||||
|
padding: 24px 5rem;
|
||||||
|
height: 80px;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
background: var(--color-background);
|
||||||
|
border-bottom: 1px solid var(--color-border-weak);
|
||||||
|
z-index: 10;
|
||||||
|
|
||||||
|
@media (max-width: 60rem) {
|
||||||
|
padding: 24px 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 34px;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="nav-desktop"] {
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 48px;
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
span {
|
||||||
|
color: var(--color-text-weak);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
text-decoration-thickness: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 40rem) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="nav-mobile"] {
|
||||||
|
button > svg {
|
||||||
|
color: var(--color-icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="nav-mobile-toggle"] {
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
outline: none;
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-right: -8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="nav-mobile-toggle"]:hover {
|
||||||
|
background: var(--color-background-weak);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="nav-mobile"] {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
@media (max-width: 40rem) {
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
[data-component="nav-mobile-icon"] {
|
||||||
|
cursor: pointer;
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="nav-mobile-menu-list"] {
|
||||||
|
position: fixed;
|
||||||
|
background: var(--color-background);
|
||||||
|
top: 80px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 20px 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 20px;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: var(--color-text-weak);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
background: var(--color-background-weak);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="logo dark"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
[data-slot="logo light"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
[data-slot="logo dark"] {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="footer"] {
|
||||||
|
border-top: 1px solid var(--color-border-weak);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
@media (max-width: 65rem) {
|
||||||
|
border-bottom: 1px solid var(--color-border-weak);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="cell"] {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 2rem 0;
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: var(--color-text-weak);
|
||||||
|
|
||||||
|
@media (max-width: 40rem) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
background: var(--color-background-weak);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
text-decoration-thickness: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="cell"] + [data-slot="cell"] {
|
||||||
|
border-left: 1px solid var(--color-border-weak);
|
||||||
|
|
||||||
|
@media (max-width: 40rem) {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile: third column on its own row */
|
||||||
|
@media (max-width: 25rem) {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
[data-slot="cell"] {
|
||||||
|
flex: 1 0 100%;
|
||||||
|
border-left: none;
|
||||||
|
border-top: 1px solid var(--color-border-weak);
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="cell"]:nth-child(1) {
|
||||||
|
border-top: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="container"] {
|
||||||
|
max-width: 67.5rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
border: 1px solid var(--color-border-weak);
|
||||||
|
border-top: none;
|
||||||
|
|
||||||
|
@media (max-width: 65rem) {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="content"] {
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="enterprise-content"] {
|
||||||
|
padding: 4rem 0;
|
||||||
|
|
||||||
|
@media (max-width: 60rem) {
|
||||||
|
padding: 2rem 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="enterprise-columns"] {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 4rem;
|
||||||
|
padding: 4rem 5rem;
|
||||||
|
|
||||||
|
@media (max-width: 80rem) {
|
||||||
|
gap: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 60rem) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 3rem;
|
||||||
|
padding: 2rem 1.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="enterprise-column-1"] {
|
||||||
|
h2 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-strong);
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-strong);
|
||||||
|
margin: 2rem 0 1rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
line-height: 1.6;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
position: relative;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--color-text);
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "•";
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
color: var(--color-background-interactive);
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: var(--color-text-strong);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="enterprise-column-2"] {
|
||||||
|
[data-component="enterprise-form"] {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-strong);
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="form-group"] {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-weak);
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:-webkit-autofill,
|
||||||
|
input:-webkit-autofill:hover,
|
||||||
|
input:-webkit-autofill:focus,
|
||||||
|
input:-webkit-autofill:active {
|
||||||
|
transition: background-color 5000000s ease-in-out 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:-webkit-autofill {
|
||||||
|
-webkit-text-fill-color: var(--color-text-strong) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:-moz-autofill {
|
||||||
|
-moz-text-fill-color: var(--color-text-strong) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
input,
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.75rem;
|
||||||
|
border: 1px solid var(--color-border-weak);
|
||||||
|
border-radius: 4px;
|
||||||
|
background: var(--color-background-weak);
|
||||||
|
color: var(--color-text-strong);
|
||||||
|
font-family: inherit;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: var(--color-text-weak);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background: var(--color-background-interactive-weaker);
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
color: var(--color-text-strong);
|
||||||
|
border: 1px solid var(--color-background-strong);
|
||||||
|
box-shadow: 0 0 0 3px var(--color-background-interactive);
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid var(--color-background-interactive)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
resize: vertical;
|
||||||
|
min-height: 120px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="submit-button"] {
|
||||||
|
padding: 0.5rem 1.5rem;
|
||||||
|
background: var(--color-background-strong);
|
||||||
|
color: var(--color-text-inverted);
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
background: var(--color-background-strong-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="success-message"] {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
background: var(--color-success);
|
||||||
|
color: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="faq"] {
|
||||||
|
border-top: 1px solid var(--color-border-weak);
|
||||||
|
padding: 4rem 5rem;
|
||||||
|
|
||||||
|
@media (max-width: 60rem) {
|
||||||
|
padding: 2rem 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="section-title"] {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--color-text-strong);
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
line-height: 200%;
|
||||||
|
|
||||||
|
@media (max-width: 60rem) {
|
||||||
|
line-height: 180%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="faq-question"] {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
color: var(--color-text-strong);
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
[data-slot="faq-icon-plus"] {
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: var(--color-text-weak);
|
||||||
|
margin-top: 2px;
|
||||||
|
|
||||||
|
[data-closed] & {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
[data-expanded] & {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[data-slot="faq-icon-minus"] {
|
||||||
|
flex-shrink: 0;
|
||||||
|
color: var(--color-text-weak);
|
||||||
|
margin-top: 2px;
|
||||||
|
|
||||||
|
[data-closed] & {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
[data-expanded] & {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[data-slot="faq-question-text"] {
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-slot="faq-answer"] {
|
||||||
|
margin-left: 40px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
color: var(--color-text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-component="legal"] {
|
||||||
|
color: var(--color-text-weak);
|
||||||
|
text-align: center;
|
||||||
|
padding: 2rem 5rem;
|
||||||
|
|
||||||
|
@media (max-width: 60rem) {
|
||||||
|
padding: 2rem 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-text-weak);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: var(--color-text-strong);
|
||||||
|
text-decoration: underline;
|
||||||
|
text-underline-offset: 2px;
|
||||||
|
text-decoration-thickness: 1px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
text-decoration-thickness: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
199
packages/console/app/src/routes/enterprise/index.tsx
Normal file
199
packages/console/app/src/routes/enterprise/index.tsx
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
import "./index.css"
|
||||||
|
import { Title, Meta } from "@solidjs/meta"
|
||||||
|
import { createSignal } from "solid-js"
|
||||||
|
import { Header } from "~/component/header"
|
||||||
|
import { Footer } from "~/component/footer"
|
||||||
|
import { Legal } from "~/component/legal"
|
||||||
|
import { Faq } from "~/component/faq"
|
||||||
|
|
||||||
|
export default function Enterprise() {
|
||||||
|
const [formData, setFormData] = createSignal({
|
||||||
|
name: "",
|
||||||
|
role: "",
|
||||||
|
email: "",
|
||||||
|
message: "",
|
||||||
|
})
|
||||||
|
const [isSubmitting, setIsSubmitting] = createSignal(false)
|
||||||
|
const [showSuccess, setShowSuccess] = createSignal(false)
|
||||||
|
|
||||||
|
const handleInputChange = (field: string) => (e: Event) => {
|
||||||
|
const target = e.target as HTMLInputElement | HTMLTextAreaElement
|
||||||
|
setFormData((prev) => ({ ...prev, [field]: target.value }))
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async (e: Event) => {
|
||||||
|
e.preventDefault()
|
||||||
|
setIsSubmitting(true)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch("/api/enterprise", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(formData()),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
setShowSuccess(true)
|
||||||
|
setFormData({
|
||||||
|
name: "",
|
||||||
|
role: "",
|
||||||
|
email: "",
|
||||||
|
message: "",
|
||||||
|
})
|
||||||
|
setTimeout(() => setShowSuccess(false), 5000)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to submit form:", error)
|
||||||
|
} finally {
|
||||||
|
setIsSubmitting(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main data-page="enterprise">
|
||||||
|
<Title>OpenCode Enterprise | How can we help your organisation?</Title>
|
||||||
|
<Meta name="description" content="Contact OpenCode for enterprise solutions" />
|
||||||
|
<div data-component="container">
|
||||||
|
<Header />
|
||||||
|
|
||||||
|
<div data-component="content">
|
||||||
|
<section data-component="enterprise-content">
|
||||||
|
<div data-component="enterprise-columns">
|
||||||
|
<div data-component="enterprise-column-1">
|
||||||
|
<h2>Your code is yours</h2>
|
||||||
|
<p>
|
||||||
|
Run OpenCode securely inside your organization with no data or context stored, and
|
||||||
|
no licensing restrictions or ownership claims. Start a trial with your team today,
|
||||||
|
then scale with enterprise features like SSO, private registries, and
|
||||||
|
self-hosting.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-component="enterprise-column-2">
|
||||||
|
<div data-component="enterprise-form">
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div data-component="form-group">
|
||||||
|
<label for="name">Full name</label>
|
||||||
|
<input
|
||||||
|
id="name"
|
||||||
|
type="text"
|
||||||
|
required
|
||||||
|
value={formData().name}
|
||||||
|
onInput={handleInputChange("name")}
|
||||||
|
placeholder="Jeff Bezos"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-component="form-group">
|
||||||
|
<label for="role">Role</label>
|
||||||
|
<input
|
||||||
|
id="role"
|
||||||
|
type="text"
|
||||||
|
required
|
||||||
|
value={formData().role}
|
||||||
|
onInput={handleInputChange("role")}
|
||||||
|
placeholder="Executive Chairman"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-component="form-group">
|
||||||
|
<label for="email">Company email</label>
|
||||||
|
<input
|
||||||
|
id="email"
|
||||||
|
type="email"
|
||||||
|
required
|
||||||
|
value={formData().email}
|
||||||
|
onInput={handleInputChange("email")}
|
||||||
|
placeholder="jeff@amazon.com"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div data-component="form-group">
|
||||||
|
<label for="message">What problem are you trying to solve?</label>
|
||||||
|
<textarea
|
||||||
|
id="message"
|
||||||
|
required
|
||||||
|
rows={5}
|
||||||
|
value={formData().message}
|
||||||
|
onInput={handleInputChange("message")}
|
||||||
|
placeholder="We need help with"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" disabled={isSubmitting()} data-component="submit-button">
|
||||||
|
{isSubmitting() ? "Sending..." : "Send"}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{showSuccess() && (
|
||||||
|
<div data-component="success-message">
|
||||||
|
Message successfully sent, we'll be in touch soon.
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section data-component="faq">
|
||||||
|
<div data-slot="section-title">
|
||||||
|
<h3>FAQ</h3>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<Faq question="Does Opencode store our code or context data?">
|
||||||
|
No. OpenCode never stores your code or context data. All
|
||||||
|
processing happens locally or directly with your AI provider.
|
||||||
|
</Faq>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Faq question="Who owns the code generated with OpenCode?">
|
||||||
|
You do. All code produced is yours, with no licensing
|
||||||
|
restrictions or ownership claims.
|
||||||
|
</Faq>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Faq
|
||||||
|
question="How can we trial OpenCode inside our organization?">
|
||||||
|
Simply install and run an internal trial with your team. Since
|
||||||
|
OpenCode doesn’t store any data, your developers can get
|
||||||
|
started right away.
|
||||||
|
</Faq>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Faq
|
||||||
|
question="What happens if someone uses the `/share` feature?">
|
||||||
|
By default, sharing is disabled. If enabled, conversations are
|
||||||
|
sent to our share service and cached through our CDN. For
|
||||||
|
enterprise use, we recommend disabling or self-hosting this
|
||||||
|
feature.
|
||||||
|
</Faq>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Faq question="Can OpenCode integrate with our company’s SSO?">
|
||||||
|
Yes. Enterprise deployments can include SSO integration so all
|
||||||
|
sessions and shared conversations are protected by your
|
||||||
|
authentication system.
|
||||||
|
</Faq>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Faq question="Can OpenCode be self-hosted?">
|
||||||
|
Absolutely. You can fully self-host OpenCode, including the share feature, ensuring that data and pages are accessible only after authentication.
|
||||||
|
</Faq>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<Faq question="How do we get started with enterprise deployment?">
|
||||||
|
Contact us to discuss pricing, implementation, and enterprise options like SSO, private registries, and self-hosting.
|
||||||
|
</Faq>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<Footer />
|
||||||
|
</div>
|
||||||
|
<Legal />
|
||||||
|
</main>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -827,12 +827,8 @@ body {
|
|||||||
outline: none;
|
outline: none;
|
||||||
border: none;
|
border: none;
|
||||||
color: var(--color-text-strong);
|
color: var(--color-text-strong);
|
||||||
|
border: 1px solid var(--color-background-strong);
|
||||||
border: 1px solid var(--color-background-strong); /* Tailwind blue-600 as example */
|
|
||||||
|
|
||||||
/* Tailwind-style ring */
|
|
||||||
box-shadow: 0 0 0 3px var(--color-background-interactive);
|
box-shadow: 0 0 0 3px var(--color-background-interactive);
|
||||||
/* mimics "ring-2 ring-blue-600/50" */
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
|||||||
@@ -55,6 +55,45 @@ We recommend you disable this for your trial.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>What is OpenCode Enterprise?</summary>
|
||||||
|
|
||||||
|
OpenCode Enterprise provides self-hosted deployment options with enhanced security, SSO integration, and dedicated support for organizations that need to maintain full control over their development environment.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>How does enterprise pricing work?</summary>
|
||||||
|
|
||||||
|
Enterprise pricing is based on team size and deployment requirements. Contact us at <a href={email}>{config.email}</a> for a custom quote based on your organization's needs.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>What deployment options are available?</summary>
|
||||||
|
|
||||||
|
We offer cloud-hosted, on-premises, and air-gapped deployment options. Each includes SSO integration, private package registry support, and customizable security configurations.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Is my data secure with enterprise?</summary>
|
||||||
|
|
||||||
|
Yes. OpenCode does not store your code or context data. All processing happens locally or through direct API calls to your AI provider. Enterprise deployments add SSO protection and can be fully air-gapped for maximum security.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Can we integrate with existing tools?</summary>
|
||||||
|
|
||||||
|
Yes. OpenCode supports private npm registries, custom authentication providers, and can be integrated into your existing CI/CD pipelines and development workflows.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
Once you have completed your trial and you are ready to self-host opencode at
|
Once you have completed your trial and you are ready to self-host opencode at
|
||||||
|
|||||||
Reference in New Issue
Block a user