diff --git a/sx/sx/docs-content.sx b/sx/sx/docs-content.sx new file mode 100644 index 0000000..7a9309a --- /dev/null +++ b/sx/sx/docs-content.sx @@ -0,0 +1,115 @@ +;; 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