;; Docs page content — fully self-contained, no Python intermediaries

(defcomp ~sx-home-content ()
  (div :id "main-content"
    (~sx-hero (highlight "(div :class \"p-4 bg-white rounded shadow\"\n  (h1 :class \"text-2xl font-bold\" \"Hello\")\n  (button :sx-get \"/api/data\"\n    :sx-target \"#result\"\n    \"Load data\"))" "lisp"))
    (~sx-philosophy)
    (~sx-how-it-works)
    (~sx-credits)))

(defcomp ~docs-introduction-content ()
  (~doc-page :title "Introduction"
    (~doc-section :title "What is sx?" :id "what"
      (p :class "text-stone-600"
        "sx is an s-expression language for building web UIs. It combines htmx's server-first hypermedia approach with React's component model. The server sends s-expression source code over the wire. The client parses, evaluates, and renders it to DOM.")
      (p :class "text-stone-600"
        "The same evaluator runs on both server (Python) and client (JavaScript). Components defined once render identically in both environments."))
    (~doc-section :title "Design decisions" :id "design"
      (p :class "text-stone-600"
        "HTML elements are first-class: (div :class \"card\" (p \"hello\")) renders exactly what you'd expect. Components use defcomp with keyword parameters and optional children. The evaluator supports let bindings, conditionals, lambda, map/filter/reduce, and ~80 primitives.")
      (p :class "text-stone-600"
        "sx replaces the pattern of shipping a JS framework + build step + client-side router + state management library just to render some server data. For most applications, sx eliminates the need for JavaScript entirely — htmx attributes handle interactivity, hyperscript handles small behaviours, and the server handles everything else."))
    (~doc-section :title "What sx is not" :id "not"
      (ul :class "space-y-2 text-stone-600"
        (li "Not a general-purpose programming language — it's a UI rendering language")
        (li "Not a full Lisp — it has macros and TCO, but no continuations or call/cc")
        (li "Not production-hardened at scale — it runs one website")))))

(defcomp ~docs-getting-started-content ()
  (~doc-page :title "Getting Started"
    (~doc-section :title "Minimal example" :id "minimal"
      (p :class "text-stone-600"
        "An sx response is s-expression source code with content type text/sx:")
      (~doc-code :code (highlight "(div :class \"p-4 bg-white rounded\"\n  (h1 :class \"text-2xl font-bold\" \"Hello, world!\")\n  (p \"This is rendered from an s-expression.\"))" "lisp"))
      (p :class "text-stone-600"
        "Add sx-get to any element to make it fetch and render sx:"))
    (~doc-section :title "Hypermedia attributes" :id "attrs"
      (p :class "text-stone-600"
        "Like htmx, sx adds attributes to HTML elements to trigger HTTP requests:")
      (~doc-code :code (highlight "(button\n  :sx-get \"/api/data\"\n  :sx-target \"#result\"\n  :sx-swap \"innerHTML\"\n  \"Load data\")" "lisp"))
      (p :class "text-stone-600"
        "sx-get, sx-post, sx-put, sx-delete, sx-patch — all work the same way. The response is parsed as sx and rendered into the target element."))))

(defcomp ~docs-components-content ()
  (~doc-page :title "Components"
    (~doc-section :title "defcomp" :id "defcomp"
      (p :class "text-stone-600"
        "Components are defined with defcomp. They take keyword parameters and optional children:")
      (~doc-code :code (highlight "(defcomp ~card (&key title subtitle &rest children)\n  (div :class \"border rounded p-4\"\n    (h2 :class \"font-bold\" title)\n    (when subtitle (p :class \"text-stone-500\" subtitle))\n    (div :class \"mt-3\" children)))" "lisp"))
      (p :class "text-stone-600"
        "Use components with the ~ prefix:")
      (~doc-code :code (highlight "(~card :title \"My Card\" :subtitle \"A description\"\n  (p \"First child\")\n  (p \"Second child\"))" "lisp")))
    (~doc-section :title "Component caching" :id "caching"
      (p :class "text-stone-600"
        "Component definitions are sent in a <script type=\"text/sx\" data-components> block. The client caches them in localStorage keyed by a content hash. On subsequent page loads, the client sends an SX-Components header listing what it has. The server only sends definitions the client is missing.")
      (p :class "text-stone-600"
        "This means the first page load sends all component definitions (~5-15KB). Subsequent navigations send zero component bytes — just the page content."))
    (~doc-section :title "Parameters" :id "params"
      (p :class "text-stone-600"
        "&key declares keyword parameters. &rest children captures remaining positional arguments. Missing parameters evaluate to nil. Components always receive all declared parameters — use (when param ...) or (if param ... ...) to handle optional values."))))

(defcomp ~docs-evaluator-content ()
  (~doc-page :title "Evaluator"
    (~doc-section :title "Special forms" :id "special"
      (p :class "text-stone-600"
        "Special forms have lazy evaluation — arguments are not evaluated before the form runs:")
      (~doc-code :code (highlight ";; Conditionals\n(if condition then-expr else-expr)\n(when condition body...)\n(cond (test1 body1) (test2 body2) (else default))\n\n;; Bindings\n(let ((name value) (name2 value2)) body...)\n(define name value)\n\n;; Functions\n(lambda (x y) (+ x y))\n(fn (x) (* x x))\n\n;; Sequencing\n(do expr1 expr2 expr3)\n(begin expr1 expr2)\n\n;; Threading\n(-> value (fn1 arg) (fn2 arg))" "lisp")))
    (~doc-section :title "Higher-order forms" :id "higher"
      (p :class "text-stone-600"
        "These operate on collections with function arguments:")
      (~doc-code :code (highlight "(map (fn (x) (* x 2)) (list 1 2 3))        ;; => (2 4 6)\n(filter (fn (x) (> x 2)) (list 1 2 3 4 5))  ;; => (3 4 5)\n(reduce (fn (acc x) (+ acc x)) 0 (list 1 2 3)) ;; => 6\n(some (fn (x) (> x 3)) (list 1 2 3 4))      ;; => true\n(every? (fn (x) (> x 0)) (list 1 2 3))      ;; => true" "lisp")))))

(defcomp ~docs-primitives-content (&key prims)
  (~doc-page :title "Primitives"
    (~doc-section :title "Built-in functions" :id "builtins"
      (p :class "text-stone-600"
        "sx provides ~80 built-in pure functions. They work identically on server (Python) and client (JavaScript).")
      (div :class "space-y-6" prims))))

(defcomp ~docs-css-content ()
  (~doc-page :title "On-Demand CSS"
    (~doc-section :title "How it works" :id "how"
      (p :class "text-stone-600"
        "sx scans every response for CSS class names used in :class attributes. It looks up only those classes in a pre-parsed Tailwind CSS registry and ships just the rules that are needed. No build step. No purging. No unused CSS.")
      (p :class "text-stone-600"
        "On the first page load, the full set of used classes is embedded in a <style> block. A hash of the class set is stored. On subsequent navigations, the client sends the hash in the SX-Css header. The server computes the diff and sends only new rules via SX-Css-Add and a <style data-sx-css> block."))
    (~doc-section :title "The protocol" :id "protocol"
      (~doc-code :code (highlight "# First page load:\nGET / HTTP/1.1\n\nHTTP/1.1 200 OK\nContent-Type: text/html\n# Full CSS in <style id=\"sx-css\"> + hash in <meta name=\"sx-css-classes\">\n\n# Subsequent navigation:\nGET /about HTTP/1.1\nSX-Css: a1b2c3d4\n\nHTTP/1.1 200 OK\nContent-Type: text/sx\nSX-Css-Hash: e5f6g7h8\nSX-Css-Add: bg-blue-500,text-white,rounded-lg\n# Only new rules in <style data-sx-css>" "bash")))
    (~doc-section :title "Advantages" :id "advantages"
      (ul :class "space-y-2 text-stone-600"
        (li "Zero build step — no Tailwind CLI, no PostCSS, no purging")
        (li "Exact CSS — never ships a rule that isn't used on the page")
        (li "Incremental — subsequent navigations only ship new rules")
        (li "Component-aware — pre-scans component definitions at registration time")))
    (~doc-section :title "Disadvantages" :id "disadvantages"
      (ul :class "space-y-2 text-stone-600"
        (li "Requires the full Tailwind CSS file loaded in memory at startup (~4MB parsed)")
        (li "Regex-based class scanning — can miss dynamically constructed class names")
        (li "No @apply support — classes must be used directly")
        (li "Tied to Tailwind's utility class naming conventions")))))

(defcomp ~docs-server-rendering-content ()
  (~doc-page :title "Server Rendering"
    (~doc-section :title "Python API" :id "python"
      (p :class "text-stone-600"
        "The server-side sx library provides several entry points for rendering:")
      (~doc-code :code (highlight "from shared.sx.helpers import sx_page, sx_response, sx_call\nfrom shared.sx.parser import SxExpr\n\n# Build a component call from Python kwargs\nsx_call(\"card\", title=\"Hello\", subtitle=\"World\")\n\n# Return an sx wire-format response\nreturn sx_response(sx_call(\"card\", title=\"Hello\"))\n\n# Return a full HTML page shell with sx boot\nreturn sx_page(ctx, page_sx)" "python")))
    (~doc-section :title "sx_call" :id "sx-call"
      (p :class "text-stone-600"
        "sx_call converts Python kwargs to an s-expression component call. Snake_case becomes kebab-case. SxExpr values are inlined without quoting. None becomes nil. Bools become true/false."))
    (~doc-section :title "sx_response" :id "sx-response"
      (p :class "text-stone-600"
        "sx_response returns a Quart Response with content type text/sx. It prepends missing component definitions, scans for CSS classes, and sets SX-Css-Hash and SX-Css-Add headers."))
    (~doc-section :title "sx_page" :id "sx-page"
      (p :class "text-stone-600"
        "sx_page returns a minimal HTML document that boots the page from sx source. The browser loads component definitions and page sx from inline <script> tags, then sx.js renders everything client-side. CSS rules are pre-scanned and injected."))))
