Rewrite landing to El component architecture
Full El component split: nav, hero, pillars, inference, pricing, footer, about, enterprise, mission, viral, local_first, comparison, efficiency, environmental. - About page rewritten first-person (Will's voice), photo included, no product spoilers - Stripe checkout wired: env() reads STRIPE_SECRET_KEY/PRICE_* at startup - Minor parent-onboarding callout added to pricing section - Inference pricing: "at cost" removed, now "priced below competitors" - Nav: wordmark image, About link active on /about - .gitignore: excludes .env, dist/, generated HTML
This commit is contained in:
+296
-4
@@ -1,7 +1,299 @@
|
||||
// main.el — Neuron landing page server
|
||||
// main.el — Neuron landing page server.
|
||||
//
|
||||
// Serves the Neuron marketing landing page at port 3001.
|
||||
// Written in El (the Engram language). Runs on the El VM (elvm).
|
||||
//
|
||||
// The El HTTP server intercepts GET / and serves __html_file__ directly.
|
||||
// We generate the page at startup with El components, write it to
|
||||
// src/index.html, and set __html_file__ to that path.
|
||||
//
|
||||
// This means the document is always El-generated — never hand-authored.
|
||||
// The El runtime serves it with the correct Content-Type: text/html header.
|
||||
//
|
||||
// Execution:
|
||||
// el run (builds + executes via the El VM)
|
||||
//
|
||||
// Routes:
|
||||
// GET / → landing page (El-rendered, served by runtime)
|
||||
// GET /api/health → {"status":"ok"}
|
||||
// GET /api/founding-count → {"remaining":N,"sold":N,"total":N}
|
||||
// GET /assets/* → static assets (served by runtime from src/assets/)
|
||||
// GET /brand/* → brand assets via handle_request
|
||||
// GET * → 404 JSON (non-/ paths not used by this SPA)
|
||||
|
||||
let html_path: String = cwd() + "/src/landing.html"
|
||||
println("Neuron landing · serving " + html_path)
|
||||
state_set("__html_file__", html_path)
|
||||
from nav import { nav }
|
||||
from hero import { hero }
|
||||
from pillars import { pillars }
|
||||
from how_it_works import { how_it_works }
|
||||
from inference import { inference }
|
||||
from efficiency import { efficiency }
|
||||
from comparison import { comparison }
|
||||
from environmental import { environmental }
|
||||
from enterprise import { enterprise }
|
||||
from mission import { mission }
|
||||
from local_first import { local_first }
|
||||
from pricing import { pricing }
|
||||
from viral import { viral }
|
||||
from footer import { footer }
|
||||
from styles import { page_open, page_close }
|
||||
from about import { about_page }
|
||||
from terms import { terms_page }
|
||||
from enterprise_terms import { enterprise_terms_page }
|
||||
|
||||
// ── Founding counter ──────────────────────────────────────────────────────────
|
||||
|
||||
let FOUNDING_TOTAL: Int = 1000
|
||||
let FOUNDING_SOLD: Int = 47
|
||||
|
||||
// ── Founding count helpers ─────────────────────────────────────────────────────
|
||||
|
||||
fn get_sold() -> Int {
|
||||
let s: String = state_get("__founding_sold__")
|
||||
if str_eq(s, "") {
|
||||
return FOUNDING_SOLD
|
||||
}
|
||||
return parse_int(s)
|
||||
}
|
||||
|
||||
fn get_total() -> Int {
|
||||
let s: String = state_get("__founding_total__")
|
||||
if str_eq(s, "") {
|
||||
return FOUNDING_TOTAL
|
||||
}
|
||||
return parse_int(s)
|
||||
}
|
||||
|
||||
// ── Page assembly ─────────────────────────────────────────────────────────────
|
||||
|
||||
fn page(sold: Int, total: Int) -> String {
|
||||
return page_open()
|
||||
+ nav()
|
||||
+ hero()
|
||||
+ pillars()
|
||||
+ how_it_works()
|
||||
+ inference()
|
||||
+ efficiency()
|
||||
+ comparison()
|
||||
+ enterprise()
|
||||
+ mission()
|
||||
+ local_first()
|
||||
+ environmental()
|
||||
+ pricing(sold, total)
|
||||
+ viral()
|
||||
+ footer()
|
||||
+ page_close()
|
||||
}
|
||||
|
||||
// ── Static asset serving ──────────────────────────────────────────────────────
|
||||
|
||||
fn read_asset(abs_path: String) -> String {
|
||||
let exists: Bool = fs_exists(abs_path)
|
||||
if !exists {
|
||||
return ""
|
||||
}
|
||||
return fs_read(abs_path)
|
||||
}
|
||||
|
||||
// ── Request handler ───────────────────────────────────────────────────────────
|
||||
//
|
||||
// NOTE: GET / is intercepted by the El HTTP runtime before reaching this
|
||||
// function — it serves __html_file__ directly with text/html.
|
||||
// This handler covers /api/* and /brand/* routes.
|
||||
|
||||
fn handle_request(method: String, path: String, body: String) -> String {
|
||||
let src_dir: String = state_get("__src_dir__")
|
||||
|
||||
// ── About page ────────────────────────────────────────────────────────────
|
||||
if str_eq(path, "/about") {
|
||||
let about_path: String = state_get("__about_html_file__")
|
||||
if !str_eq(about_path, "") {
|
||||
return fs_read(about_path)
|
||||
}
|
||||
return "{\"__status__\":404,\"error\":\"not found\"}"
|
||||
}
|
||||
|
||||
// ── Terms of Service ──────────────────────────────────────────────────────
|
||||
if str_eq(path, "/legal/terms") {
|
||||
let terms_path: String = state_get("__terms_html_file__")
|
||||
if !str_eq(terms_path, "") {
|
||||
return fs_read(terms_path)
|
||||
}
|
||||
return "{\"__status__\":404,\"error\":\"not found\"}"
|
||||
}
|
||||
|
||||
// ── Enterprise Agreement ──────────────────────────────────────────────────
|
||||
if str_eq(path, "/legal/enterprise-terms") {
|
||||
let ent_path: String = state_get("__enterprise_terms_html_file__")
|
||||
if !str_eq(ent_path, "") {
|
||||
return fs_read(ent_path)
|
||||
}
|
||||
return "{\"__status__\":404,\"error\":\"not found\"}"
|
||||
}
|
||||
|
||||
// ── Health check ──────────────────────────────────────────────────────────
|
||||
if str_eq(path, "/api/health") {
|
||||
return "{\"status\":\"ok\",\"service\":\"neuron-landing\"}"
|
||||
}
|
||||
|
||||
// ── Founding count ────────────────────────────────────────────────────────
|
||||
if str_eq(path, "/api/founding-count") {
|
||||
let sold: Int = get_sold()
|
||||
let total: Int = get_total()
|
||||
let remaining: Int = total - sold
|
||||
let sold_s: String = int_to_str(sold)
|
||||
let total_s: String = int_to_str(total)
|
||||
let rem_s: String = int_to_str(remaining)
|
||||
return "{\"sold\":" + sold_s + ",\"total\":" + total_s + ",\"remaining\":" + rem_s + "}"
|
||||
}
|
||||
|
||||
// ── Brand assets: /brand/* ────────────────────────────────────────────────
|
||||
if str_starts_with(path, "/brand/") {
|
||||
let rel: String = str_slice(path, 7, str_len(path))
|
||||
let abs: String = src_dir + "/brand/" + rel
|
||||
let content: String = read_asset(abs)
|
||||
if str_eq(content, "") {
|
||||
return "{\"__status__\":404,\"error\":\"not found\"}"
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
// ── Stripe checkout ───────────────────────────────────────────────────────
|
||||
if str_eq(path, "/api/checkout") {
|
||||
let stripe_key: String = state_get("__stripe_secret_key__")
|
||||
if str_eq(stripe_key, "") {
|
||||
return "{\"__status__\":503,\"error\":\"Stripe not configured\"}"
|
||||
}
|
||||
let plan: String = "founding"
|
||||
if str_contains(body, "\"professional\"") {
|
||||
plan = "professional"
|
||||
}
|
||||
let origin: String = "http://localhost:3001"
|
||||
let price_id: String = ""
|
||||
let mode: String = "subscription"
|
||||
if str_eq(plan, "founding") {
|
||||
price_id = state_get("__stripe_price_founding__")
|
||||
mode = "payment"
|
||||
}
|
||||
if str_eq(plan, "professional") {
|
||||
price_id = state_get("__stripe_price_professional__")
|
||||
mode = "subscription"
|
||||
}
|
||||
if str_eq(price_id, "") {
|
||||
return "{\"__status__\":503,\"error\":\"Plan price not configured\"}"
|
||||
}
|
||||
let form_body: String = "mode=" + mode
|
||||
+ "&line_items[0][price]=" + price_id
|
||||
+ "&line_items[0][quantity]=1"
|
||||
+ "&success_url=" + origin + "/marketplace/success?session_id={CHECKOUT_SESSION_ID}"
|
||||
+ "&cancel_url=" + origin + "/#pricing"
|
||||
+ "&allow_promotion_codes=true"
|
||||
+ "&metadata[plan]=" + plan
|
||||
let response: String = http_post_form_auth(
|
||||
"https://api.stripe.com/v1/checkout/sessions",
|
||||
stripe_key,
|
||||
form_body
|
||||
)
|
||||
if str_contains(response, "\"url\"") {
|
||||
return response
|
||||
}
|
||||
return "{\"__status__\":500,\"error\":\"Stripe session creation failed\"}"
|
||||
}
|
||||
|
||||
// ── Stripe webhook ────────────────────────────────────────────────────────
|
||||
if str_eq(path, "/api/webhooks/stripe") {
|
||||
if str_contains(body, "checkout.session.completed") {
|
||||
let license_api: String = state_get("__license_api_url__")
|
||||
if !str_eq(license_api, "") {
|
||||
let resp: String = http_post(license_api + "/api/v1/webhooks/stripe", body)
|
||||
println("[webhook] forwarded to license API: " + resp)
|
||||
}
|
||||
}
|
||||
return "{\"received\":true}"
|
||||
}
|
||||
|
||||
// ── Checkout success ──────────────────────────────────────────────────────
|
||||
if str_eq(path, "/marketplace/success") {
|
||||
return page_open() + "
|
||||
<div style=\"min-height:80vh;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:4rem 2rem\">
|
||||
<p class=\"label\" style=\"margin-bottom:1.5rem\">Purchase complete</p>
|
||||
<h1 class=\"display-lg\" style=\"margin-bottom:1.25rem\">Welcome to Neuron.</h1>
|
||||
<p style=\"font-family:var(--body);font-weight:300;font-size:1.1rem;color:var(--t2);max-width:28rem;line-height:1.7;margin-bottom:2.5rem\">
|
||||
Your license is being provisioned. Check your email in the next few minutes — your license key and download instructions will be waiting.
|
||||
</p>
|
||||
<a href=\"/\" class=\"btn-primary\">Back to home →</a>
|
||||
</div>
|
||||
" + page_close()
|
||||
}
|
||||
|
||||
// ── Fallback ──────────────────────────────────────────────────────────────
|
||||
return "{\"__status__\":404,\"error\":\"not found\"}"
|
||||
}
|
||||
|
||||
// ── Startup ───────────────────────────────────────────────────────────────────
|
||||
//
|
||||
// 1. Generate the landing page HTML using El components.
|
||||
// 2. Write it to src/index.html (El-generated, never hand-authored).
|
||||
// 3. Set __html_file__ so the El HTTP runtime serves it for GET /.
|
||||
// The runtime also uses __html_file__'s parent dir for /assets/* serving.
|
||||
|
||||
let src_dir: String = cwd() + "/src"
|
||||
let html_path: String = src_dir + "/index.html"
|
||||
|
||||
// Generate page HTML with founding counter seed values.
|
||||
let page_html: String = page(FOUNDING_SOLD, FOUNDING_TOTAL)
|
||||
|
||||
// Write El-generated HTML to disk.
|
||||
fs_write(html_path, page_html)
|
||||
|
||||
// Generate about page HTML.
|
||||
let about_html_path: String = src_dir + "/about.html"
|
||||
let about_html: String = page_open() + about_page() + page_close()
|
||||
fs_write(about_html_path, about_html)
|
||||
|
||||
// Generate terms pages HTML.
|
||||
let terms_html_path: String = src_dir + "/terms.html"
|
||||
let ent_terms_html_path: String = src_dir + "/enterprise-terms.html"
|
||||
fs_write(terms_html_path, terms_page())
|
||||
fs_write(ent_terms_html_path, enterprise_terms_page())
|
||||
|
||||
// Register with El HTTP runtime.
|
||||
state_set("__html_file__", html_path)
|
||||
state_set("__about_html_file__", about_html_path)
|
||||
state_set("__terms_html_file__", terms_html_path)
|
||||
state_set("__enterprise_terms_html_file__", ent_terms_html_path)
|
||||
state_set("__src_dir__", src_dir)
|
||||
state_set("__founding_sold__", int_to_str(FOUNDING_SOLD))
|
||||
state_set("__founding_total__", int_to_str(FOUNDING_TOTAL))
|
||||
|
||||
// Stripe config from environment.
|
||||
let stripe_key: String = env("STRIPE_SECRET_KEY")
|
||||
let stripe_price_founding: String = env("STRIPE_PRICE_FOUNDING")
|
||||
let stripe_price_professional: String = env("STRIPE_PRICE_PROFESSIONAL")
|
||||
let license_api_url: String = env("NEURON_LICENSE_API_URL")
|
||||
state_set("__stripe_secret_key__", stripe_key)
|
||||
state_set("__stripe_price_founding__", stripe_price_founding)
|
||||
state_set("__stripe_price_professional__", stripe_price_professional)
|
||||
state_set("__license_api_url__", license_api_url)
|
||||
|
||||
println(color_bold("Neuron landing") + " — http://localhost:3001")
|
||||
println(" HTML generated by El → " + html_path)
|
||||
println(" About generated by El → " + about_html_path)
|
||||
println(" Terms generated by El → " + terms_html_path)
|
||||
println(" Ent. Terms generated by El → " + ent_terms_html_path)
|
||||
println(" Assets → " + src_dir + "/assets/")
|
||||
println("")
|
||||
println(" Routes:")
|
||||
println(" GET / → El-generated landing page")
|
||||
println(" GET /about → El-generated about page")
|
||||
println(" GET /legal/terms → Consumer terms of service")
|
||||
println(" GET /legal/enterprise-terms → Enterprise agreement")
|
||||
println(" GET /api/health → health check")
|
||||
println(" GET /api/founding-count → founding counter JSON")
|
||||
println(" POST /api/checkout → Stripe checkout session")
|
||||
println(" POST /api/webhooks/stripe → Stripe webhook")
|
||||
println(" GET /marketplace/success → post-purchase success page")
|
||||
println(" GET /assets/* → static files")
|
||||
println(" GET /brand/* → brand files")
|
||||
println("")
|
||||
|
||||
http_serve(3001)
|
||||
|
||||
Reference in New Issue
Block a user