Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions components/ConceptaHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,9 @@ const PILLARS = [
/* ── Per-project window visuals ──────────────────────────────────────
Each block echoes the visual signature of its product page: Mix shows
a style snippet, Remix its component catalog, Naked UI its observable state,
Ack a validation result, FVM a pinned SDK, Stargate a governed workflow, and
Code Analysis a scorecard. Same chrome, different content. */
Ack a validation result, FVM a pinned SDK, Rockets its configuration plan,
Stargate a governed workflow, and Code Analysis a scorecard. Same chrome,
different content. */

const MIX_SNIPPET = `final cardStyle = BoxStyler()
.color(Colors.blue)
Expand Down Expand Up @@ -198,6 +199,28 @@ function FvmVisual() {
);
}

function RocketsVisual() {
return (
<div className="pv-graph">
<div className="pv-graph-node">
<span className="pv-graph-dot" />
<span className="pv-graph-name">options</span>
<span className="pv-graph-comp">auth · resources · repository</span>
</div>
<div className="pv-graph-edge">createServer · no generated files</div>
<div className="pv-graph-node">
<span className="pv-graph-dot" />
<span className="pv-graph-name">server</span>
<span className="pv-graph-comp">/me · /pets · /api</span>
</div>
<div className="pv-graph-run">
<Check size={13} strokeWidth={2.4} />
identity · CRUD · hooks · OpenAPI
</div>
</div>
);
}

function StargateVisual() {
return (
<div className="pv-graph">
Expand Down Expand Up @@ -324,6 +347,17 @@ const PROJECTS: Project[] = [
external: true,
Visual: FvmVisual,
},
{
name: "Rockets",
tagline: "Describe the backend. Ship the domain.",
description:
"One typed backend definition wires identity, storage, resources, access, hooks, and OpenAPI at runtime.",
href: "/rockets",
accent: "#FF5906",
status: "Open source",
windowLabel: "server.ts",
Visual: RocketsVisual,
},
{
name: "Stargate",
tagline: "Complex workflows for the enterprise.",
Expand Down
14 changes: 13 additions & 1 deletion components/FloatingNavbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
MIX_GITHUB_URL,
NAKED_UI_GITHUB_URL,
REMIX_GITHUB_URL,
ROCKETS_GITHUB_URL,
} from './constants'

function DiscordIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
Expand All @@ -29,7 +30,7 @@ function DiscordIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
)
}

type ProductId = 'concepta' | 'mix' | 'remix' | 'naked-ui' | 'ack' | 'stargate' | 'code-analysis' | 'voyager'
type ProductId = 'concepta' | 'mix' | 'remix' | 'naked-ui' | 'ack' | 'rockets' | 'stargate' | 'code-analysis' | 'voyager'

function getActiveProduct(pathname: string | null): ProductId {
if (!pathname) return 'concepta'
Expand All @@ -41,6 +42,7 @@ function getActiveProduct(pathname: string | null): ProductId {
if (pathname === '/naked-ui' || pathname.startsWith('/naked-ui/')) return 'naked-ui'
if (pathname.startsWith('/documentation/ack')) return 'ack'
if (pathname === '/ack' || pathname.startsWith('/ack/')) return 'ack'
if (pathname === '/rockets' || pathname.startsWith('/rockets/')) return 'rockets'
if (pathname === '/stargate' || pathname.startsWith('/stargate/')) return 'stargate'
if (pathname === '/code-analysis' || pathname.startsWith('/code-analysis/')) return 'code-analysis'
if (pathname === '/voyager' || pathname.startsWith('/voyager/')) return 'voyager'
Expand All @@ -64,13 +66,15 @@ const MIX_DOCS_URL = '/documentation/mix/overview/introduction'
const REMIX_DOCS_URL = '/documentation/remix'
const NAKED_UI_DOCS_URL = 'https://docs.page/btwld/naked_ui'
const ACK_DOCS_URL = '/documentation/ack/getting-started/overview'
const ROCKETS_DOCS_URL = 'https://github.com/btwld/rockets#readme'

// Stargate and Code Analysis have no public docs or repos yet.
function getDocsHref(product: ProductId): string | null {
if (product === 'mix') return MIX_DOCS_URL
if (product === 'remix') return REMIX_DOCS_URL
if (product === 'naked-ui') return NAKED_UI_DOCS_URL
if (product === 'ack') return ACK_DOCS_URL
if (product === 'rockets') return ROCKETS_DOCS_URL
return null
}

Expand All @@ -80,6 +84,7 @@ function getGithubHref(product: ProductId): string | null {
if (product === 'remix') return REMIX_GITHUB_URL
if (product === 'naked-ui') return NAKED_UI_GITHUB_URL
if (product === 'ack') return ACK_GITHUB_URL
if (product === 'rockets') return ROCKETS_GITHUB_URL
return null
}

Expand Down Expand Up @@ -126,6 +131,13 @@ const PRODUCTS: Product[] = [
logo: '/assets/logo_ack_sidebar.svg',
showLabel: true,
},
{
id: 'rockets' as const,
label: 'Rockets',
href: '/rockets',
logo: '/assets/logo_rockets_mark.svg',
showLabel: true,
},
{
id: 'stargate' as const,
label: 'Stargate',
Expand Down
25 changes: 24 additions & 1 deletion components/ProductFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@

import Link from 'next/link'
import { usePathname } from 'next/navigation'
import { CONCEPTA_GITHUB_URL, MIX_GITHUB_URL, REMIX_GITHUB_URL } from './constants'
import {
CONCEPTA_GITHUB_URL,
MIX_GITHUB_URL,
REMIX_GITHUB_URL,
ROCKETS_GITHUB_URL,
} from './constants'

function isAckPath(pathname: string | null) {
return pathname === '/ack'
Expand All @@ -14,6 +19,10 @@ function isNakedUiPath(pathname: string | null) {
return pathname === '/naked-ui' || pathname?.startsWith('/naked-ui/')
}

function isRocketsPath(pathname: string | null) {
return pathname === '/rockets' || pathname?.startsWith('/rockets/')
}

function isRemixPath(pathname: string | null) {
return pathname === '/remix'
|| pathname?.startsWith('/remix/')
Expand Down Expand Up @@ -42,6 +51,7 @@ function isProductWithoutPublicRepo(pathname: string | null) {
function getGithubHref(pathname: string | null) {
if (isRemixPath(pathname)) return REMIX_GITHUB_URL
if (isMixPath(pathname)) return MIX_GITHUB_URL
if (isRocketsPath(pathname)) return ROCKETS_GITHUB_URL
if (isProductWithoutPublicRepo(pathname)) return null
return CONCEPTA_GITHUB_URL
}
Expand Down Expand Up @@ -82,6 +92,19 @@ export default function ProductFooter() {
)
}

if (isRocketsPath(pathname)) {
return (
<div className="flex flex-col sm:flex-row items-center justify-between w-full gap-4 text-sm text-[var(--mix-text-muted)]">
<span>Describe the backend. Ship the domain.</span>
<div className="flex items-center gap-5">
<a href={ROCKETS_GITHUB_URL} target="_blank" rel="noopener noreferrer" className="hover:text-white transition-colors">GitHub</a>
<a href="https://www.npmjs.com/package/@bitwild/rockets" target="_blank" rel="noopener noreferrer" className="hover:text-white transition-colors">npm</a>
<a href={ROCKETS_GITHUB_URL + '#readme'} target="_blank" rel="noopener noreferrer" className="hover:text-white transition-colors">Guide</a>
</div>
</div>
)
}

// Public products link their own repo/package. Concepta pages link the org,
// while products without a public repo omit GitHub, matching the navbar.
const githubHref = getGithubHref(pathname)
Expand Down
1 change: 1 addition & 0 deletions components/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export const MIX_GITHUB_URL = 'https://github.com/btwld/mix'
export const REMIX_GITHUB_URL = 'https://github.com/btwld/remix'
export const NAKED_UI_GITHUB_URL = 'https://github.com/btwld/naked_ui'
export const ACK_GITHUB_URL = 'https://github.com/btwld/ack'
export const ROCKETS_GITHUB_URL = 'https://github.com/btwld/rockets'
15 changes: 15 additions & 0 deletions components/landing/LandingButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import clsx from "clsx";
import Link from "next/link";
import React from "react";
import type { LandingCta } from "./types";

function ArrowIcon(props: React.ComponentPropsWithoutRef<"svg">) {
return (
Expand Down Expand Up @@ -72,3 +73,17 @@ export function LandingButton({
</Link>
);
}

export function LandingCtaButton({ cta }: { cta: LandingCta }) {
return (
<LandingButton
href={cta.href}
variant={cta.variant}
arrow={cta.arrow}
target={cta.external ? "_blank" : undefined}
rel={cta.external ? "noopener noreferrer" : undefined}
>
{cta.label}
</LandingButton>
);
}
Loading
Loading