From f2ab12e65bb204fc074e1c53307d19a263e1e4e0 Mon Sep 17 00:00:00 2001 From: Will Anderson Date: Fri, 8 May 2026 22:14:38 -0500 Subject: [PATCH] feat(native-el-ui): rewrite checkout/main to use el-html vessel, fix page_close linker error - checkout.el and main.el: replace raw import of el-html vessel with direct extern fn declarations; implementations come from dist/elhtml_impl.c (c_source) - Add src/elhtml.el as reference file (all el-html extern fn declarations; not imported) - dist/elhtml_impl.c: pre-compiled el-html vessel C (strips int main + sample global) - dist/page_close.c: pre-compiled page_close implementation; elc OOMs after emitting the ~71KB page_open body and silently drops page_close, so supply it as c_source - manifest.el: add elhtml_impl.c and page_close.c as c_source entries - .gitignore: un-ignore dist/elhtml_impl.c and dist/page_close.c --- .gitignore | 2 + dist/elhtml_impl.c | 341 ++++++++++++++++++++++++++++++++ dist/page_close.c | 12 ++ manifest.el | 2 + src/checkout.el | 478 +++++++++++++++++++++++++++------------------ src/elhtml.el | 45 +++++ src/main.el | 357 +++++++++++++++++++-------------- 7 files changed, 909 insertions(+), 328 deletions(-) create mode 100644 dist/elhtml_impl.c create mode 100644 dist/page_close.c create mode 100644 src/elhtml.el diff --git a/.gitignore b/.gitignore index e00e6d4..4b6c875 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,7 @@ src/assets/js/ !dist/web_stubs.c !dist/vessel_stubs.c !dist/soul-demo.c +!dist/page_close.c +!dist/elhtml_impl.c !dist/entrypoint.sh !dist/engram-snapshot.json diff --git a/dist/elhtml_impl.c b/dist/elhtml_impl.c new file mode 100644 index 0000000..a6ae454 --- /dev/null +++ b/dist/elhtml_impl.c @@ -0,0 +1,341 @@ +#include +#include +#include "el_runtime.h" + +el_val_t el_escape(el_val_t s); +el_val_t el_text(el_val_t s); +el_val_t el_attr(el_val_t name, el_val_t value); +el_val_t el_div(el_val_t attrs, el_val_t children); +el_val_t el_section(el_val_t attrs, el_val_t children); +el_val_t el_article(el_val_t attrs, el_val_t children); +el_val_t el_header(el_val_t attrs, el_val_t children); +el_val_t el_footer(el_val_t attrs, el_val_t children); +el_val_t el_main(el_val_t attrs, el_val_t children); +el_val_t el_nav(el_val_t attrs, el_val_t children); +el_val_t el_aside(el_val_t attrs, el_val_t children); +el_val_t el_ul(el_val_t attrs, el_val_t children); +el_val_t el_ol(el_val_t attrs, el_val_t children); +el_val_t el_li(el_val_t attrs, el_val_t children); +el_val_t el_p(el_val_t attrs, el_val_t children); +el_val_t el_span(el_val_t attrs, el_val_t children); +el_val_t el_form(el_val_t attrs, el_val_t children); +el_val_t el_h1(el_val_t attrs, el_val_t text); +el_val_t el_h2(el_val_t attrs, el_val_t text); +el_val_t el_h3(el_val_t attrs, el_val_t text); +el_val_t el_h4(el_val_t attrs, el_val_t text); +el_val_t el_button(el_val_t attrs, el_val_t label); +el_val_t el_a(el_val_t href, el_val_t attrs, el_val_t children); +el_val_t el_input(el_val_t type_attr, el_val_t attrs); +el_val_t el_textarea(el_val_t attrs, el_val_t value); +el_val_t el_label(el_val_t for_id, el_val_t attrs, el_val_t children); +el_val_t el_img(el_val_t src, el_val_t alt, el_val_t attrs); +el_val_t el_video(el_val_t attrs, el_val_t children); +el_val_t el_strong(el_val_t children); +el_val_t el_em(el_val_t children); +el_val_t el_code(el_val_t children); +el_val_t el_pre(el_val_t attrs, el_val_t children); +el_val_t el_hr(void); +el_val_t el_br(void); +el_val_t el_html_doc(el_val_t lang, el_val_t head_html, el_val_t body_html); +el_val_t el_meta(el_val_t name, el_val_t content); +el_val_t el_meta_charset(el_val_t charset); +el_val_t el_link_stylesheet(el_val_t href); +el_val_t el_script_src(el_val_t src, el_val_t defer_load); +el_val_t el_script_inline(el_val_t js); +el_val_t el_title(el_val_t text); + + +el_val_t el_escape(el_val_t s) { + s = str_replace(s, EL_STR("&"), EL_STR("&")); + s = str_replace(s, EL_STR("<"), EL_STR("<")); + s = str_replace(s, EL_STR(">"), EL_STR(">")); + s = str_replace(s, EL_STR("\""), EL_STR(""")); + return str_replace(s, EL_STR("'"), EL_STR("'")); + return 0; +} + +el_val_t el_text(el_val_t s) { + return el_escape(s); + return 0; +} + +el_val_t el_attr(el_val_t name, el_val_t value) { + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR(" "), name), EL_STR("=\"")), el_escape(value)), EL_STR("\"")); + return 0; +} + +el_val_t el_div(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("
"), children), EL_STR("
")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("
")), children), EL_STR("
")); + return 0; +} + +el_val_t el_section(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("
"), children), EL_STR("
")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("
")), children), EL_STR("
")); + return 0; +} + +el_val_t el_article(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("
"), children), EL_STR("
")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("
")), children), EL_STR("
")); + return 0; +} + +el_val_t el_header(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("
"), children), EL_STR("
")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("
")), children), EL_STR("
")); + return 0; +} + +el_val_t el_footer(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("
"), children), EL_STR("
")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("
")), children), EL_STR("
")); + return 0; +} + +el_val_t el_main(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("
"), children), EL_STR("
")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("
")), children), EL_STR("
")); + return 0; +} + +el_val_t el_nav(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_aside(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_ul(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("
    "), children), EL_STR("
")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("
    ")), children), EL_STR("
")); + return 0; +} + +el_val_t el_ol(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("
    "), children), EL_STR("
")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("
    ")), children), EL_STR("
")); + return 0; +} + +el_val_t el_li(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("
  • "), children), EL_STR("
  • ")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("
  • ")), children), EL_STR("
  • ")); + return 0; +} + +el_val_t el_p(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("

    "), children), EL_STR("

    ")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("

    ")), children), EL_STR("

    ")); + return 0; +} + +el_val_t el_span(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR(""), children), EL_STR("")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")), children), EL_STR("")); + return 0; +} + +el_val_t el_form(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("
    "), children), EL_STR("
    ")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("
    ")), children), EL_STR("
    ")); + return 0; +} + +el_val_t el_h1(el_val_t attrs, el_val_t text) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("

    "), el_escape(text)), EL_STR("

    ")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("

    ")), el_escape(text)), EL_STR("

    ")); + return 0; +} + +el_val_t el_h2(el_val_t attrs, el_val_t text) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("

    "), el_escape(text)), EL_STR("

    ")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("

    ")), el_escape(text)), EL_STR("

    ")); + return 0; +} + +el_val_t el_h3(el_val_t attrs, el_val_t text) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("

    "), el_escape(text)), EL_STR("

    ")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("

    ")), el_escape(text)), EL_STR("

    ")); + return 0; +} + +el_val_t el_h4(el_val_t attrs, el_val_t text) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("

    "), el_escape(text)), EL_STR("

    ")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("

    ")), el_escape(text)), EL_STR("

    ")); + return 0; +} + +el_val_t el_button(el_val_t attrs, el_val_t label) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_a(el_val_t href, el_val_t attrs, el_val_t children) { + el_val_t h = el_str_concat(el_str_concat(EL_STR("href=\""), el_escape(href)), EL_STR("\"")); + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")), children), EL_STR("")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")), children), EL_STR("")); + return 0; +} + +el_val_t el_input(el_val_t type_attr, el_val_t attrs) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_textarea(el_val_t attrs, el_val_t value) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_label(el_val_t for_id, el_val_t attrs, el_val_t children) { + el_val_t f = el_str_concat(el_str_concat(EL_STR("for=\""), el_escape(for_id)), EL_STR("\"")); + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_img(el_val_t src, el_val_t alt, el_val_t attrs) { + el_val_t base = el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("src=\""), el_escape(src)), EL_STR("\" alt=\"")), el_escape(alt)), EL_STR("\"")); + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_video(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_strong(el_val_t children) { + return el_str_concat(el_str_concat(EL_STR(""), children), EL_STR("")); + return 0; +} + +el_val_t el_em(el_val_t children) { + return el_str_concat(el_str_concat(EL_STR(""), children), EL_STR("")); + return 0; +} + +el_val_t el_code(el_val_t children) { + return el_str_concat(el_str_concat(EL_STR(""), children), EL_STR("")); + return 0; +} + +el_val_t el_pre(el_val_t attrs, el_val_t children) { + if (str_eq(attrs, EL_STR(""))) { + return el_str_concat(el_str_concat(EL_STR("
    "), children), EL_STR("
    ")); + } + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("
    ")), children), EL_STR("
    ")); + return 0; +} + +el_val_t el_hr(void) { + return EL_STR("
    "); + return 0; +} + +el_val_t el_br(void) { + return EL_STR("
    "); + return 0; +} + +el_val_t el_html_doc(el_val_t lang, el_val_t head_html, el_val_t body_html) { + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")), head_html), EL_STR("")), body_html), EL_STR("")); + return 0; +} + +el_val_t el_meta(el_val_t name, el_val_t content) { + return el_str_concat(el_str_concat(el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_meta_charset(el_val_t charset) { + return el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_link_stylesheet(el_val_t href) { + return el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_script_src(el_val_t src, el_val_t defer_load) { + if (defer_load) { + return el_str_concat(el_str_concat(EL_STR("")); + } + return el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_script_inline(el_val_t js) { + return el_str_concat(el_str_concat(EL_STR("")); + return 0; +} + +el_val_t el_title(el_val_t text) { + return el_str_concat(el_str_concat(EL_STR(""), el_escape(text)), EL_STR("")); + return 0; +} + + diff --git a/dist/page_close.c b/dist/page_close.c new file mode 100644 index 0000000..0bbf0b6 --- /dev/null +++ b/dist/page_close.c @@ -0,0 +1,12 @@ +#include +#include +#include "el_runtime.h" + +el_val_t page_close(void); + +el_val_t page_close(void) { + el_val_t widgets = ({ el_val_t _html_1 = EL_STR(""); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("TryNeuron")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("Neuron")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("LiveDemo")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("Send")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("Preview")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("Thisiswhatyouareabouttopublish")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("times;")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("Cancel")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("Publishtogallery")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1 = el_str_concat(_html_1, EL_STR("")); _html_1; }); + return el_str_concat(widgets, EL_STR("")); + return 0; +} + diff --git a/manifest.el b/manifest.el index 23836a4..a8db0d9 100644 --- a/manifest.el +++ b/manifest.el @@ -11,4 +11,6 @@ build { output "dist/" c_source "dist/web_stubs.c" c_source "dist/vessel_stubs.c" + c_source "dist/elhtml_impl.c" + c_source "dist/page_close.c" } diff --git a/src/checkout.el b/src/checkout.el index 6a953df..48c02e4 100644 --- a/src/checkout.el +++ b/src/checkout.el @@ -11,15 +11,63 @@ // 4. User fills name, email, card - submits // 5. stripe.confirmPayment() → redirects to /marketplace/success +// el-html vessel — extern declarations (implementations in dist/elhtml_impl.c) +extern fn el_escape(s: String) -> String +extern fn el_text(s: String) -> String +extern fn el_attr(name: String, value: String) -> String +extern fn el_div(attrs: String, children: String) -> String +extern fn el_section(attrs: String, children: String) -> String +extern fn el_article(attrs: String, children: String) -> String +extern fn el_header(attrs: String, children: String) -> String +extern fn el_footer(attrs: String, children: String) -> String +extern fn el_main(attrs: String, children: String) -> String +extern fn el_nav(attrs: String, children: String) -> String +extern fn el_aside(attrs: String, children: String) -> String +extern fn el_ul(attrs: String, children: String) -> String +extern fn el_ol(attrs: String, children: String) -> String +extern fn el_li(attrs: String, children: String) -> String +extern fn el_p(attrs: String, children: String) -> String +extern fn el_span(attrs: String, children: String) -> String +extern fn el_form(attrs: String, children: String) -> String +extern fn el_h1(attrs: String, text: String) -> String +extern fn el_h2(attrs: String, text: String) -> String +extern fn el_h3(attrs: String, text: String) -> String +extern fn el_h4(attrs: String, text: String) -> String +extern fn el_button(attrs: String, label: String) -> String +extern fn el_a(href: String, attrs: String, children: String) -> String +extern fn el_input(type_attr: String, attrs: String) -> String +extern fn el_textarea(attrs: String, value: String) -> String +extern fn el_label(for_id: String, attrs: String, children: String) -> String +extern fn el_img(src: String, alt: String, attrs: String) -> String +extern fn el_strong(children: String) -> String +extern fn el_em(children: String) -> String +extern fn el_code(children: String) -> String +extern fn el_pre(attrs: String, children: String) -> String +extern fn el_hr() -> String +extern fn el_br() -> String +extern fn el_html_doc(lang: String, head_html: String, body_html: String) -> String +extern fn el_meta(name: String, content: String) -> String +extern fn el_meta_charset(charset: String) -> String +extern fn el_link_stylesheet(href: String) -> String +extern fn el_script_src(src: String, defer_load: Bool) -> String +extern fn el_script_inline(js: String) -> String +extern fn el_title(text: String) -> String + +fn el_style_block(css: String) -> String { + "" +} + fn checkout_nav_html() -> String { - + let logo_img: String = el_img( + "/assets/brand/neuron-wordmark-on-light.png", + "Neuron", + "srcset=\"/assets/brand/neuron-wordmark-on-light@2x.png 2x\" height=\"28\"" + ) + let logo_link: String = el_a("/", "class=\"nav-logo\" aria-label=\"Neuron home\"", logo_img) + let back_link: String = el_a("/", "class=\"nav-link\"", "← Back") + let nav_links: String = el_div("class=\"nav-links\"", back_link) + let nav_inner: String = el_div("class=\"nav-inner\"", logo_link + nav_links) + el_nav("id=\"nav\"", nav_inner) } fn checkout_page(plan: String, pub_key: String) -> String { @@ -38,216 +86,276 @@ fn checkout_page(plan: String, pub_key: String) -> String { let plan_cadence: String = if is_founding { "one-time" } else { if is_free { "forever" } else { "billed monthly" } } let features_html: String = if is_founding { - "
  • Everything in Professional - forever
  • -
  • Neuron Inference when it launches - priced below the major APIs, forever
  • -
  • Never pay again - lifetime updates included
  • -
  • Founding member badge in the app
  • -
  • Private founding member community
  • -
  • Shape the roadmap - your votes carry more weight
  • -
  • Beta features before general release
  • -
  • Name in the credits
  • " + el_li("", "Everything in Professional - forever") + + el_li("", "Neuron Inference when it launches - priced below the major APIs, forever") + + el_li("", "Never pay again - lifetime updates included") + + el_li("", "Founding member badge in the app") + + el_li("", "Private founding member community") + + el_li("", "Shape the roadmap - your votes carry more weight") + + el_li("", "Beta features before general release") + + el_li("", "Name in the credits") } else { if is_free { - "
  • Persistent memory - never resets
  • -
  • Local inference via Ollama (coming)
  • -
  • Bring your own API keys
  • -
  • 3 marketplace plugins included
  • -
  • Core built-in capabilities
  • -
  • 2 devices included
  • " + el_li("", "Persistent memory - never resets") + + el_li("", "Local inference via Ollama (coming)") + + el_li("", "Bring your own API keys") + + el_li("", "3 marketplace plugins included") + + el_li("", "Core built-in capabilities") + + el_li("", "2 devices included") } else { - "
  • Persistent memory - never resets
  • -
  • Bring your own API keys (OpenAI, Anthropic, Grok...)
  • -
  • Neuron Inference when it launches - Q3 2026, priced below the major APIs
  • -
  • Unlimited projects
  • -
  • Full plugin marketplace
  • -
  • IDE, Slack, and more integrations
  • -
  • Early access to new features
  • -
  • 2 devices included
  • " + el_li("", "Persistent memory - never resets") + + el_li("", "Bring your own API keys (OpenAI, Anthropic, Grok...)") + + el_li("", "Neuron Inference when it launches - Q3 2026, priced below the major APIs") + + el_li("", "Unlimited projects") + + el_li("", "Full plugin marketplace") + + el_li("", "IDE, Slack, and more integrations") + + el_li("", "Early access to new features") + + el_li("", "2 devices included") } } let nav_html: String = checkout_nav_html() - let main_html: String =
    -
    + // ── Order summary (left column) ─────────────────────────────────────────── - -
    -

    Your order

    + let price_row: String = el_div( + "style=\"display: flex; align-items: baseline; gap: .5rem; margin-top: 1.25rem;\"", + el_span("class=\"checkout-price\"", el_text(plan_price)) + + el_span("class=\"checkout-cadence\"", el_text(plan_cadence)) + ) -
    -

    {plan_name}

    -

    {plan_desc}

    -
    - {plan_price} - {plan_cadence} -
    -
    + let plan_block: String = el_div( + "style=\"margin-bottom: 2rem;\"", + el_p("class=\"checkout-plan-name\"", el_text(plan_name)) + + el_p("class=\"checkout-plan-desc\"", el_text(plan_desc)) + + price_row + ) - + let summary_col: String = el_div( + "class=\"checkout-summary\"", + el_p("class=\"label\" style=\"margin-bottom: 1.5rem; color: var(--navy);\"", "Your order") + + plan_block + + el_div("class=\"navy-line-left\" style=\"width: 3rem; margin-bottom: 1.75rem;\"", "") + + el_ul("class=\"checkout-features\"", features_html) + + el_p("class=\"checkout-guarantee\"", "Your data stays yours. Runs locally. No telemetry.") + ) -
      - {raw(features_html)} -
    + // ── Auth section ────────────────────────────────────────────────────────── -

    - Your data stays yours. Runs locally. No telemetry. -

    -
    + let auth_heading: String = if is_free { + el_p("class=\"label\" style=\"margin-bottom: 1.5rem; color: var(--navy);\"", "Create your account.") + + el_p("class=\"checkout-auth-hint\" style=\"margin-bottom: 2rem;\"", "No card required. Your account is free, forever.") + } else { + el_p("class=\"label\" style=\"margin-bottom: 1.25rem;\"", "Sign in (optional)") + + el_p("class=\"checkout-auth-hint\"", "Sign in to link this purchase to an existing account. Or skip and create one later - we'll match it to your email.") + } - -
    + let google_svg: String = "" + + "" + + "" + + "" + + "" + + "" - -
    - " + (if is_free { " -

    Create your account.

    -

    No card required. Your account is free, forever.

    - " } else { " -

    Sign in (optional)

    -

    Sign in to link this purchase to an existing account. Or skip and create one later - we'll match it to your email.

    - " }) + " + let github_svg: String = "" + + "" + + "" -
    - - -
    + let social_btns: String = el_div( + "class=\"checkout-social-btns\"", + "" + + "" + ) - + let auth_message: String = el_div("id=\"auth-message\" class=\"checkout-message\" style=\"display:none;\"", "") -
    - or {#if is_free}create an account with email{#else}create an account{/if} -
    + let divider_label: String = if is_free { + "or create an account with email" + } else { + "or create an account" + } -
    - - - -

    Already have an account? Sign in

    -
    -
    + let auth_divider: String = el_div( + "class=\"checkout-auth-divider\"", + el_span("id=\"auth-divider-label\"", divider_label) + ) - - " + (if is_free { " -
    -
    -

    You're in.

    -

    Your free account is ready. Download Neuron to get started.

    - Go to your account → -
    - " } else { "" }) + " + let create_btn_label: String = if is_free { "Create account →" } else { "Create account →" } - -
    - - {#if is_free}{#else} -

    Already have an account? Sign in to link your purchase.

    - {/if} + let email_auth_form: String = el_div( + "id=\"email-auth-form\"", + el_input("email", "id=\"auth-email\" class=\"checkout-input\" placeholder=\"Email address\" autocomplete=\"email\" style=\"width:100%;display:block;margin-bottom:.75rem\"") + + el_input("password", "id=\"auth-password\" class=\"checkout-input\" placeholder=\"Password - min 8 characters\" autocomplete=\"new-password\" style=\"width:100%;display:block;margin-bottom:.75rem\"") + + "" + + el_p("class=\"checkout-auth-hint\" style=\"margin-top:.75rem;text-align:center\"", + "Already have an account? " + + el_a("#", "onclick=\"showSignIn();return false;\" style=\"color:var(--navy)\"", "Sign in") + ) + ) - - {#if is_founding} -
    -

    Before you continue

    -

    Founding Member is not a ceremonial title. These are the people who will work directly with the team to shape what Neuron becomes. You will have a real voice in what gets built, and we will take it seriously. That requires you to show up in good faith.

    - - -
    - {/if} + let auth_section_style: String = if is_free { "" } else { "display:none;" } + let auth_section: String = el_div( + "id=\"auth-section\" style=\"" + auth_section_style + "\"", + auth_heading + social_btns + auth_message + auth_divider + email_auth_form + ) - - {#if is_founding}{#else}{#if is_free}{#else} -
    -

    When would you like to be charged?

    -
    - - -
    -
    - {/if}{/if} + // ── Free-tier success panel ─────────────────────────────────────────────── -

    Payment

    + let free_success: String = if is_free { + el_div( + "id=\"free-success\" style=\"display:none; text-align:center; padding: 2.5rem 1rem;\"", + el_div("style=\"font-size:2.5rem; margin-bottom:1.25rem;\"", "✓") + + el_p("class=\"label\" style=\"margin-bottom:.75rem; color:var(--navy);\"", "You're in.") + + el_p("class=\"checkout-auth-hint\" style=\"margin-bottom:2rem;\"", "Your free account is ready. Download Neuron to get started.") + + el_a("/marketplace", "class=\"checkout-submit\" style=\"display:inline-block; text-decoration:none; padding:.875rem 2rem;\"", "Go to your account →") + ) + } else { "" } -
    + // ── Payment section ─────────────────────────────────────────────────────── -
    -
    - - -
    -
    - - -
    -
    + let payment_section_style: String = if is_free { "display:none;" } else { "" } -
    -
    - -
    Loading payment form…
    -
    -
    + let auth_badge: String = el_div("id=\"auth-badge\" style=\"display:none; margin-bottom: 1.5rem;\"", "") - + let signin_prompt: String = if is_free { "" } else { + el_p( + "class=\"checkout-auth-hint\" id=\"signin-prompt\" style=\"margin-bottom:1.25rem;font-size:.8125rem\"", + "Already have an account? " + + el_a( + "#", + "onclick=\"document.getElementById('auth-section').style.display='';this.parentNode.style.display='none';return false;\" style=\"color:var(--navy);text-decoration:underline\"", + "Sign in" + ) + + " to link your purchase." + ) + } - + let founding_attestation: String = if is_founding { + el_div( + "id=\"founding-attestation\" style=\"margin-bottom:2rem;padding:1.5rem;border:1px solid rgba(0,82,160,.2);background:rgba(0,82,160,.03)\"", + el_p("style=\"font-family:var(--body);font-weight:500;font-size:.9rem;color:var(--t1);margin-bottom:.75rem\"", "Before you continue") + + el_p("style=\"font-family:var(--body);font-weight:300;font-size:.8375rem;color:var(--t2);line-height:1.75;margin-bottom:1.25rem\"", + "Founding Member is not a ceremonial title. These are the people who will work directly with the team to shape what Neuron becomes. You will have a real voice in what gets built, and we will take it seriously. That requires you to show up in good faith." + ) + + "" + + el_p("id=\"attest-warn\" style=\"display:none;font-family:var(--body);font-size:.8rem;color:#c44;margin-top:.75rem\"", "Please confirm the above before continuing.") + ) + } else { "" } -

    - - Secured by Stripe  ·  256-bit TLS  ·  PCI DSS compliant -

    + let charge_timing: String = if is_founding || is_free { "" } else { + el_div( + "style=\"margin-bottom:1.75rem\"", + el_p("class=\"label\" style=\"margin-bottom:1rem\"", "When would you like to be charged?") + + el_div( + "style=\"display:flex;flex-direction:column;gap:.625rem\"", + "" + + "" + ) + ) + } -
    -
    -
    + let security_svg: String = "" + + "" + + "" + + "" -
    -
    + let submit_label: String = if is_free { "Reserve free tier →" } else { "Complete purchase →" } + + let payment_form: String = el_form( + "id=\"payment-form\" autocomplete=\"on\"", + el_div( + "class=\"checkout-field-group\"", + el_div("class=\"checkout-field\"", + el_label("buyer-name", "class=\"checkout-label\"", "Full name") + + el_input("text", "id=\"buyer-name\" name=\"name\" autocomplete=\"name\" class=\"checkout-input\" placeholder=\"Full name\" required") + ) + + el_div("class=\"checkout-field\"", + el_label("buyer-email", "class=\"checkout-label\"", "Email") + + el_input("email", "id=\"buyer-email\" name=\"email\" autocomplete=\"email\" class=\"checkout-input\" placeholder=\"you@example.com\" required") + ) + ) + + el_div( + "class=\"checkout-payment-element-wrap\"", + el_div("id=\"payment-element\"", + el_div("class=\"checkout-element-loading\"", "Loading payment form…") + ) + ) + + el_div("id=\"payment-message\" class=\"checkout-message\" style=\"display:none;\"", "") + + "" + + el_p("class=\"checkout-security\"", + security_svg + + " Secured by Stripe  ·  256-bit TLS  ·  PCI DSS compliant" + ) + ) + + let payment_section: String = el_div( + "id=\"payment-section\" style=\"" + payment_section_style + "\"", + auth_badge + + signin_prompt + + founding_attestation + + charge_timing + + el_p("class=\"label\" style=\"margin-bottom: 1.75rem;\"", "Payment") + + payment_form + ) + + // ── Right column ────────────────────────────────────────────────────────── + + let form_wrap: String = el_div( + "class=\"checkout-form-wrap\"", + auth_section + free_success + payment_section + ) + + // ── Full page shell ─────────────────────────────────────────────────────── + + let checkout_shell: String = el_div("class=\"checkout-shell\"", summary_col + form_wrap) + + let main_html: String = el_main( + "style=\"min-height: 100vh; padding: clamp(6rem, 14vh, 9rem) 2rem 4rem;\"", + checkout_shell + ) let style_html: String = checkout_style_html() - let free_init_script: String = if is_free { "" } else { "" } - return nav_html + main_html + "" + style_html + "" + free_init_script + let supabase_script: String = el_script_src("https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2/dist/umd/supabase.js", false) + let stripe_script: String = "" + let auth_script: String = el_script_src("/js/checkout-auth.js", true) + let cfg_js: String = "window.NEURON_CFG=window.NEURON_CFG||{};window.NEURON_CFG.plan=\"" + plan + "\";window.NEURON_CFG.pub_key=\"" + pub_key + "\";" + let cfg_script: String = el_script_inline(cfg_js) + let stripe_el_script: String = el_script_src("/js/checkout-stripe.js", true) + let free_init_script: String = if is_free { + el_script_inline("document.addEventListener('DOMContentLoaded',function(){window.neuronCheckoutFree&&window.neuronCheckoutFree()});") + } else { "" } + + return nav_html + main_html + supabase_script + stripe_script + style_html + auth_script + cfg_script + stripe_el_script + free_init_script } fn checkout_style_html() -> String { - +.checkout-auth-badge strong { color: var(--navy); font-weight: 500; }" + el_style_block(css) } diff --git a/src/elhtml.el b/src/elhtml.el new file mode 100644 index 0000000..ae6bab4 --- /dev/null +++ b/src/elhtml.el @@ -0,0 +1,45 @@ +// elhtml.el — extern declarations for the el-html vessel. +// The implementations live in dist/elhtml.c (pre-compiled). +// Import this file instead of the vessel source directly. + +extern fn el_escape(s: String) -> String +extern fn el_text(s: String) -> String +extern fn el_attr(name: String, value: String) -> String +extern fn el_div(attrs: String, children: String) -> String +extern fn el_section(attrs: String, children: String) -> String +extern fn el_article(attrs: String, children: String) -> String +extern fn el_header(attrs: String, children: String) -> String +extern fn el_footer(attrs: String, children: String) -> String +extern fn el_main(attrs: String, children: String) -> String +extern fn el_nav(attrs: String, children: String) -> String +extern fn el_aside(attrs: String, children: String) -> String +extern fn el_ul(attrs: String, children: String) -> String +extern fn el_ol(attrs: String, children: String) -> String +extern fn el_li(attrs: String, children: String) -> String +extern fn el_p(attrs: String, children: String) -> String +extern fn el_span(attrs: String, children: String) -> String +extern fn el_form(attrs: String, children: String) -> String +extern fn el_h1(attrs: String, text: String) -> String +extern fn el_h2(attrs: String, text: String) -> String +extern fn el_h3(attrs: String, text: String) -> String +extern fn el_h4(attrs: String, text: String) -> String +extern fn el_button(attrs: String, label: String) -> String +extern fn el_a(href: String, attrs: String, children: String) -> String +extern fn el_input(type_attr: String, attrs: String) -> String +extern fn el_textarea(attrs: String, value: String) -> String +extern fn el_label(for_id: String, attrs: String, children: String) -> String +extern fn el_img(src: String, alt: String, attrs: String) -> String +extern fn el_video(attrs: String, children: String) -> String +extern fn el_strong(children: String) -> String +extern fn el_em(children: String) -> String +extern fn el_code(children: String) -> String +extern fn el_pre(attrs: String, children: String) -> String +extern fn el_hr() -> String +extern fn el_br() -> String +extern fn el_html_doc(lang: String, head_html: String, body_html: String) -> String +extern fn el_meta(name: String, content: String) -> String +extern fn el_meta_charset(charset: String) -> String +extern fn el_link_stylesheet(href: String) -> String +extern fn el_script_src(src: String, defer_load: Bool) -> String +extern fn el_script_inline(js: String) -> String +extern fn el_title(text: String) -> String diff --git a/src/main.el b/src/main.el index 09c249e..305b7df 100644 --- a/src/main.el +++ b/src/main.el @@ -21,6 +21,48 @@ // GET /brand/* → brand assets via handle_request // GET * → 404 JSON (non-/ paths not used by this SPA) +// el-html vessel — extern declarations (implementations in dist/elhtml_impl.c) +extern fn el_escape(s: String) -> String +extern fn el_text(s: String) -> String +extern fn el_attr(name: String, value: String) -> String +extern fn el_div(attrs: String, children: String) -> String +extern fn el_section(attrs: String, children: String) -> String +extern fn el_article(attrs: String, children: String) -> String +extern fn el_header(attrs: String, children: String) -> String +extern fn el_footer(attrs: String, children: String) -> String +extern fn el_main(attrs: String, children: String) -> String +extern fn el_nav(attrs: String, children: String) -> String +extern fn el_aside(attrs: String, children: String) -> String +extern fn el_ul(attrs: String, children: String) -> String +extern fn el_ol(attrs: String, children: String) -> String +extern fn el_li(attrs: String, children: String) -> String +extern fn el_p(attrs: String, children: String) -> String +extern fn el_span(attrs: String, children: String) -> String +extern fn el_form(attrs: String, children: String) -> String +extern fn el_h1(attrs: String, text: String) -> String +extern fn el_h2(attrs: String, text: String) -> String +extern fn el_h3(attrs: String, text: String) -> String +extern fn el_h4(attrs: String, text: String) -> String +extern fn el_button(attrs: String, label: String) -> String +extern fn el_a(href: String, attrs: String, children: String) -> String +extern fn el_input(type_attr: String, attrs: String) -> String +extern fn el_textarea(attrs: String, value: String) -> String +extern fn el_label(for_id: String, attrs: String, children: String) -> String +extern fn el_img(src: String, alt: String, attrs: String) -> String +extern fn el_strong(children: String) -> String +extern fn el_em(children: String) -> String +extern fn el_code(children: String) -> String +extern fn el_pre(attrs: String, children: String) -> String +extern fn el_hr() -> String +extern fn el_br() -> String +extern fn el_html_doc(lang: String, head_html: String, body_html: String) -> String +extern fn el_meta(name: String, content: String) -> String +extern fn el_meta_charset(charset: String) -> String +extern fn el_link_stylesheet(href: String) -> String +extern fn el_script_src(src: String, defer_load: Bool) -> String +extern fn el_script_inline(js: String) -> String +extern fn el_title(text: String) -> String + from nav import { nav } from hero import { hero } from pillars import { pillars } @@ -193,140 +235,167 @@ fn share_card_page(question: String, answer_plain: String, answer_html_in: Strin // TikTok and Snapchat have no web URL share scheme — use clipboard copy let tiktok_copy_text: String = "Copied+%E2%80%94+paste+into+TikTok" let snap_copy_text: String = "Copied+%E2%80%94+paste+into+Snapchat" - return - - - - -Things Neuron Said - - - - - - - - - - - - - - -
    - -
    -
    -
    {raw(q_html)}
    -
    -
    -
    -
    - Neuron -
    {raw(a_html)}
    -
    -
    -
    + let cfg_js: String = "window.NEURON_CFG=window.NEURON_CFG||{};window.NEURON_CFG.id=\"" + id + "\";window.NEURON_CFG.card_url=\"" + card_url + "\";" -
    - Helpful? - - 0 - -
    + // ── Head ────────────────────────────────────────────────────────────────── - + let share_css: String = "*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}" + + ":root{--navy:#0052A0;--navy-dark:#003d7a;--t1:#0D0D14;--t2:#3A3A4A;--t3:#6B6B7E;--bg:#FAFAF8}" + + "body{font-family:'IBM Plex Sans',system-ui,sans-serif;background:var(--bg);color:var(--t1);min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:2rem 1rem}" + + "body::before{content:'';position:fixed;inset:0;pointer-events:none;z-index:0;background-image:linear-gradient(rgba(0,0,0,.018) 1px,transparent 1px),linear-gradient(90deg,rgba(0,0,0,.018) 1px,transparent 1px);background-size:48px 48px}" + + ".page{width:100%;max-width:580px;display:flex;flex-direction:column;gap:1.75rem;position:relative;z-index:1}" + + ".page-header{display:flex;align-items:center;justify-content:space-between;gap:1rem}" + + ".wordmark img{height:22px;width:auto;display:block}" + + ".eyebrow{font-size:.65rem;font-weight:400;letter-spacing:.16em;text-transform:uppercase;color:var(--t3)}" + + ".chat-frame{background:#fff;border:1px solid rgba(0,0,0,.09);box-shadow:0 4px 32px rgba(0,0,0,.07),0 1px 4px rgba(0,0,0,.04);padding:1.5rem;display:flex;flex-direction:column;gap:1rem}" + + ".chat-row-user{display:flex;flex-direction:row-reverse}" + + ".chat-row-ai{display:flex;flex-direction:row;align-items:flex-end;gap:.625rem}" + + ".bubble-user{background:#0052A0;color:#fff;border-radius:18px 18px 4px 18px;padding:11px 15px;max-width:78%;font-size:.875rem;line-height:1.55;word-break:break-word}" + + ".bubble-ai{background:var(--bg);color:var(--t1);border:1px solid rgba(0,0,0,.07);border-radius:18px 18px 18px 4px;padding:11px 15px;max-width:88%;font-size:.875rem;font-weight:300;line-height:1.65;word-break:break-word;box-shadow:0 2px 6px rgba(0,0,0,.05)}" + + ".bubble-ai p{margin:0}" + + ".bubble-ai p+p{margin-top:.6rem}" + + ".bubble-ai ul,.bubble-ai ol{margin:.5rem 0 .5rem 1.25rem;padding:0}" + + ".bubble-ai li+li{margin-top:.25rem}" + + ".bubble-ai strong{font-weight:600}" + + ".bubble-ai em{font-style:italic}" + + ".bubble-ai code{font-family:'IBM Plex Mono','Menlo',monospace;font-size:.8rem;background:rgba(0,0,0,.05);padding:1px 4px;border-radius:3px}" + + ".bubble-ai pre{background:rgba(0,0,0,.05);padding:.75rem;border-radius:6px;overflow-x:auto;font-size:.8rem;margin:.5rem 0}" + + ".bubble-ai pre code{background:none;padding:0}" + + ".bubble-ai blockquote{border-left:3px solid rgba(0,82,160,.3);margin:.5rem 0;padding:.25rem 0 .25rem .75rem;color:var(--t2)}" + + ".bubble-ai h1,.bubble-ai h2,.bubble-ai h3,.bubble-ai h4{font-weight:600;margin:.5rem 0 .25rem}" + + ".bubble-ai h1{font-size:1.05rem}.bubble-ai h2{font-size:1rem}.bubble-ai h3{font-size:.95rem}.bubble-ai h4{font-size:.9rem}" + + ".bubble-ai a{color:var(--navy);text-decoration:underline}" + + ".ai-col{display:flex;flex-direction:column;gap:.25rem}" + + ".ai-label{font-size:.6rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--navy)}" + + ".avatar{width:26px;height:26px;border-radius:50%;flex-shrink:0;background:#fff;border:1px solid rgba(0,82,160,.15);display:flex;align-items:center;justify-content:center}" + + ".avatar img{width:14px;height:14px;object-fit:contain}" + + ".vote-row{display:flex;align-items:center;gap:.75rem}" + + ".vote-label{font-size:.65rem;font-weight:400;letter-spacing:.12em;text-transform:uppercase;color:var(--t3)}" + + ".vote-btn{background:none;border:1px solid rgba(0,0,0,.12);cursor:pointer;padding:.3rem .6rem;font-size:.8rem;color:var(--t2);transition:all .15s;line-height:1}" + + ".vote-btn:hover{border-color:var(--navy);color:var(--navy)}" + + ".vote-btn.voted-up{background:var(--navy);color:#fff;border-color:var(--navy)}" + + ".vote-btn.voted-down{background:#f0f0ec;color:var(--t3);border-color:rgba(0,0,0,.12)}" + + ".vote-count{font-size:.8rem;font-weight:500;color:var(--t1);min-width:1.5rem;text-align:center}" + + ".share-section{display:flex;flex-direction:column;gap:.625rem}" + + ".share-label{font-size:.65rem;font-weight:500;letter-spacing:.12em;text-transform:uppercase;color:var(--t3)}" + + ".share-row{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}" + + ".share-btn{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border-radius:50%;border:none;text-decoration:none;cursor:pointer;transition:opacity .15s,transform .15s;flex-shrink:0}" + + ".share-btn:hover{opacity:.85;transform:scale(1.08)}" + + ".share-btn.copied{outline:2px solid var(--navy)}" + + ".divider{height:1px;background:rgba(0,0,0,.07)}" + + ".footer-row{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap}" + + ".footer-note{font-size:.75rem;color:var(--t3)}" + + ".cta-btn{display:inline-flex;align-items:center;gap:.5rem;background:var(--navy);color:#fff;text-decoration:none;font-size:.7rem;font-weight:500;letter-spacing:.14em;text-transform:uppercase;padding:.7rem 1.4rem;white-space:nowrap;transition:background .15s}" + + ".cta-btn:hover{background:var(--navy-dark)}" + + "@media(max-width:480px){.chat-frame{padding:1.25rem}.footer-row{flex-direction:column;align-items:flex-start}}" -
    + let head_html: String = el_meta_charset("UTF-8") + + "" + + el_title("Things Neuron Said") + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" - -
    - - - + // ── Body ────────────────────────────────────────────────────────────────── + + let wordmark_link: String = el_a( + "https://neurontechnologies.ai", + "class=\"wordmark\"", + el_img( + "/assets/brand/neuron-wordmark-on-light.png", + "Neuron", + "srcset=\"/assets/brand/neuron-wordmark-on-light@2x.png 2x\" height=\"22\"" + ) + ) + + let page_header: String = el_div( + "class=\"page-header\"", + wordmark_link + el_span("class=\"eyebrow\"", "Things Neuron Said") + ) + + let user_bubble: String = el_div("class=\"chat-row-user\"", + el_div("class=\"bubble-user\"", q_html) + ) + + let avatar: String = el_div("class=\"avatar\"", + el_img("/assets/neuron-icon.png", "", "") + ) + + let ai_col: String = el_div("class=\"ai-col\"", + el_span("class=\"ai-label\"", "Neuron") + + el_div("class=\"bubble-ai\"", a_html) + ) + + let ai_bubble: String = el_div("class=\"chat-row-ai\"", avatar + ai_col) + + let chat_frame: String = el_div("class=\"chat-frame\"", user_bubble + ai_bubble) + + let vote_row: String = el_div( + "class=\"vote-row\"", + el_span("class=\"vote-label\"", "Helpful?") + + "" + + el_span("class=\"vote-count\" id=\"vote-score\"", "0") + + "" + ) + + let share_row: String = el_div( + "class=\"share-row\"", + el_a(x_href, "target=\"_blank\" rel=\"noopener\" class=\"share-btn\" title=\"Post on X\" style=\"background:#000\"", + el_img("/assets/social/x.svg", "X", "width=\"18\" height=\"18\"") + ) + + el_a(li_href, "target=\"_blank\" rel=\"noopener\" class=\"share-btn\" title=\"Share on LinkedIn\" style=\"background:transparent\"", + el_img("/assets/social/linkedin.png", "LinkedIn", "width=\"18\" height=\"18\"") + ) + + el_a(fb_href, "target=\"_blank\" rel=\"noopener\" class=\"share-btn\" title=\"Share on Facebook\" style=\"background:#1877F2\"", + el_img("/assets/social/facebook.svg", "Facebook", "width=\"18\" height=\"18\"") + ) + + el_a(wa_href, "target=\"_blank\" rel=\"noopener\" class=\"share-btn\" title=\"Send via WhatsApp\" style=\"background:#25D366\"", + el_img("/assets/social/whatsapp.svg", "WhatsApp", "width=\"18\" height=\"18\"") + ) + + "" + + "" + ) + + let share_section: String = el_div( + "class=\"share-section\"", + el_span("class=\"share-label\"", "Share") + share_row + ) + + let footer_row: String = el_div( + "class=\"footer-row\"", + el_span("class=\"footer-note\"", "From a live conversation with Neuron.") + + el_a("https://neurontechnologies.ai", "class=\"cta-btn\"", "Try Neuron ↗") + ) + + let page_div: String = el_div( + "class=\"page\"", + page_header + + chat_frame + + vote_row + + share_section + + el_div("class=\"divider\"", "") + + footer_row + ) + + let body_html: String = page_div + + el_script_inline(cfg_js) + + el_script_src("/js/main.js", true) + + el_html_doc("en", head_html, body_html) } // ── Static asset serving ────────────────────────────────────────────────────── @@ -1643,20 +1712,22 @@ fn handle_request_inner(method: String, path: String, body: String) -> String { if str_starts_with(path, "/marketplace/success") { let badge_html: String = founding_badge(get_sold()) let badge_css: String = founding_badge_css() - return page_open() + badge_css + " -
    -

    You're in.

    -

    Welcome to Neuron.

    -

    - Your license is being provisioned. Check your email - your license key and download instructions will be there in the next few minutes. -

    -
    " + badge_html + "
    - -
    -" + page_close() + let success_body: String = el_div( + "style=\"min-height:80vh;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:4rem 2rem\"", + el_p("class=\"label\" style=\"margin-bottom:1.5rem\"", "You're in.") + + el_h1("class=\"display-lg\" style=\"margin-bottom:1.25rem\"", "Welcome to Neuron.") + + el_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:3rem\"", + "Your license is being provisioned. Check your email - your license key and download instructions will be there in the next few minutes." + ) + + el_div("style=\"margin-bottom:3rem\"", badge_html) + + el_div( + "style=\"display:flex;gap:1rem;flex-wrap:wrap;justify-content:center\"", + el_a("/account", "class=\"btn-primary\"", "View your account →") + + el_a("/", "class=\"btn-ghost\"", "Back to home") + ) + ) + return page_open() + badge_css + success_body + page_close() } // ── Account dashboard ─────────────────────────────────────────────────────