pub fn Page(ctx: zx.PageContext) !zx.Component {
    // var page_timer = std.time.Timer.start() catch unreachable;
    const allocator = ctx.arena;

    // std.log.info("\x1b[1;36m[DOCS PAGE] Starting page generation...\x1b[0m", .{});

    // If example
    var aw_if: std.io.Writer.Allocating = .init(allocator);
    const zx_example_if = @embedFile("../examples/if.zx");
    const zig_example_if = @embedFile("../examples/if.zig");
    const html_page_if = @import("../examples/if.zig").Conditional(allocator);
    html_page_if.render(&aw_if.writer) catch unreachable;
    const html_example_if = allocator.dupe(u8, aw_if.written()) catch unreachable;

    // Switch example
    var aw_switch: std.io.Writer.Allocating = .init(allocator);
    const zx_example_switch = @embedFile("../examples/switch.zx");
    const zig_example_switch = @embedFile("../examples/switch.zig");
    const html_page_switch = @import("../examples/switch.zig").RoleSwitch(allocator);
    html_page_switch.render(&aw_switch.writer) catch unreachable;
    const html_example_switch = allocator.dupe(u8, aw_switch.written()) catch unreachable;

    // For example
    var aw_for: std.io.Writer.Allocating = .init(allocator);
    const zx_example_for = @embedFile("../examples/for.zx");
    const zig_example_for = @embedFile("../examples/for.zig");
    const html_page_for = @import("../examples/for.zig").UserList(allocator);
    html_page_for.render(&aw_for.writer) catch unreachable;
    const html_example_for = allocator.dupe(u8, aw_for.written()) catch unreachable;

    // While example
    var aw_while: std.io.Writer.Allocating = .init(allocator);
    const zx_example_while = @embedFile("../examples/while.zx");
    const zig_example_while = @embedFile("../examples/while.zig");
    const html_page_while = @import("../examples/while.zig").Counter(allocator);
    html_page_while.render(&aw_while.writer) catch unreachable;
    const html_example_while = allocator.dupe(u8, aw_while.written()) catch unreachable;

    // Expression example
    var aw_expr: std.io.Writer.Allocating = .init(allocator);
    const zx_example_expr = @embedFile("../examples/text.zx");
    const zig_example_expr = @embedFile("../examples/text.zig");
    const html_page_expr = try @import("../examples/text.zig").Expressions(allocator);
    html_page_expr.render(&aw_expr.writer) catch unreachable;
    const html_example_expr = allocator.dupe(u8, aw_expr.written()) catch unreachable;

    // Components example
    var aw_components: std.io.Writer.Allocating = .init(allocator);
    const zx_example_components = @embedFile("../examples/components.zx");
    const zig_example_components = @embedFile("../examples/components.zig");
    const html_page_components = @import("../examples/components.zig").ButtonDemo(ctx);
    html_page_components.render(&aw_components.writer) catch unreachable;
    const html_example_components = allocator.dupe(u8, aw_components.written()) catch unreachable;

    // Routing example
    var aw_routing: std.io.Writer.Allocating = .init(allocator);
    const zx_example_routing = @embedFile("../examples/routing.zx");
    const zig_example_routing = @embedFile("../examples/routing.zig");
    const html_page_routing = @import("../examples/routing.zig").Page(ctx);
    html_page_routing.render(&aw_routing.writer) catch unreachable;
    const html_example_routing = allocator.dupe(u8, aw_routing.written()) catch unreachable;

    // Layout example - use simple example like learn page
    var aw_layout: std.io.Writer.Allocating = .init(allocator);
    const zx_example_layout = @embedFile("../learn/examples/layout_example.zx");
    const zig_example_layout = @embedFile("../learn/examples/.zx/layout_example.zig");
    const layoutctx = zx.LayoutContext.init(ctx.request, ctx.response, ctx.allocator);
    const html_page_layout = @import("../learn/examples/.zx/layout_example.zig").Layout(layoutctx, zx.Component{ .text = "Hello, World!" });
    html_page_layout.render(&aw_layout.writer) catch unreachable;
    const html_example_layout = allocator.dupe(u8, aw_layout.written()) catch unreachable;

    // Allocator example
    var aw_allocator: std.io.Writer.Allocating = .init(allocator);
    const zx_example_allocator = @embedFile("../examples/allocator.zx");
    const zig_example_allocator = @embedFile("../examples/allocator.zig");
    const html_page_allocator = @import("../examples/allocator.zig").AllocatorDemo(ctx);
    html_page_allocator.render(&aw_allocator.writer) catch unreachable;
    const html_example_allocator = allocator.dupe(u8, aw_allocator.written()) catch unreachable;

    const expr_syntax = "{expression}";

    // Expression type examples
    const expr_string_example =
        \\const name = "Alice";
        \\...
        \\(<p>{name}</p>) // <p>Alice</p>
    ;
    const expr_int_example =
        \\const count: u32 = 42;
        \\...
        \\(<p>{count}</p>) // <p>42</p>
    ;
    const expr_float_example =
        \\const price: f32 = 19.99;
        \\...
        \\(<p>${price}</p>) // <p>$19.99</p>
    ;
    const expr_bool_example =
        \\const active = true;
        \\...
        \\(<p>{active}</p>) // <p>true</p>
    ;
    const expr_enum_example =
        \\const Status = enum { pending, approved, rejected };
        \\const status = Status.approved;
        \\...
        \\(<p>{status}</p>) // <p>approved</p>
    ;
    const expr_optional_example =
        \\const maybe_name: ?[]const u8 = "Bob";
        \\...
        \\(<p>{maybe_name}</p>) // <p>Bob</p>
        \\
        \\
        \\const no_name: ?[]const u8 = null;
        \\...
        \\(<p>{no_name}</p>) // <p></p> (empty)
    ;
    const expr_component_example =
        \\const header = Header(allocator);
        \\...
        \\(<div>{header}</div>) // Renders the Header component
    ;
    const expr_component_array_example =
        \\const items: []zx.Component = &.{ Item("A"), Item("B") };
        \\...
        \\(<ul>{items}</ul>) // Renders both Item components
    ;

    // Control flow capture examples
    const optional_capture_example =
        \\const user_name: ?[]const u8 = "Alice";
        \\...
        \\{if (user_name) |name| (<p>Welcome, {name}!</p>)}
        \\
        \\// With else branch:
        \\{if (user_name) |name| (<p>Hello, {name}</p>) else (<p>Guest</p>)}
        \\
        \\// While with capture (iterator pattern):
        \\{while (iter.next()) |item| (<li>{item}</li>)}
    ;
    const error_capture_example =
        \\// If with error capture:
        \\{if (fetchUser()) |user| (
        \\    <p>Welcome, {user.name}!</p>
        \\) else |err| (
        \\    <p>Error: {@errorName(err)}</p>
        \\)}
        \\
        \\// While with error capture:
        \\{while (iter.next()) |item| (
        \\    <li>{item}</li>
        \\) else |err| (
        \\    <p>Iteration ended: {@errorName(err)}</p>
        \\)}
    ;

    // Attribute examples
    const spread_attrs_example =
        \\const form_attrs = .{
        \\    .class = "form-control",
        \\    .@"data-validate" = "true",
        \\};
        \\const input_props = .{ .name = "email", .value = "test@example.com" };
        \\...
        \\(<form {..form_attrs}>
        \\    <input type="text" {..input_props} />
        \\</form>)
    ;
    const shorthand_attrs_example =
        \\const class = "btn-primary";
        \\const disabled = true;
        \\const @"data-id" = "123";
        \\...
        \\(<button {class} {disabled} {@"data-id"}>Click</button>)
        \\// Renders: <button class="btn-primary" disabled data-id="123">Click</button>
    ;
    const template_attrs_example =
        \\const count = 42;
        \\const name = "John";
        \\...
        \\(<div class=`item-{count}` data-user=`user-{name}`>
        \\    <a href=`/users/{name}/profile`>Profile</a>
        \\</div>)
        \\// Renders: <div class="item-42" data-user="user-John">
        \\//            <a href="/users/John/profile">Profile</a>
        \\//          </div>
    ;

    // Component context examples
    const component_ctx_example =
        \\// ComponentContext: children only, no custom props
        \\fn Wrapper(ctx: *zx.ComponentContext) zx.Component {
        \\    return (
        \\        <div @allocator={ctx.allocator} class="wrapper">
        \\            {ctx.children}
        \\        </div>
        \\    );
        \\}
    ;
    const component_ctx_props_example =
        \\// ComponentCtx(Props): props and children access
        \\const CardProps = struct { title: []const u8 };
        \\fn Card(ctx: *zx.ComponentCtx(CardProps)) zx.Component {
        \\    return (
        \\        <article @allocator={ctx.allocator} class="card">
        \\            <h2>{ctx.props.title}</h2>
        \\            {ctx.children}
        \\        </article>
        \\    );
        \\}
    ;

    // Syntax examples
    const multiline_string_example =
        \\// Multiline strings use Zig's \\ syntax:
        \\(<pre>{
        \\    \\const x = 1;
        \\    \\const y = 2;
        \\    \\const sum = x + y;
        \\}</pre>)
    ;
    const comments_example =
        \\// Single-line comments are supported in ZX:
        \\(<div>
        \\    // This is a comment
        \\    <p>Visible content</p>
        \\    // Another comment
        \\</div>)
    ;

    // Escaping example
    var aw_escaping: std.io.Writer.Allocating = .init(allocator);
    const zx_example_escaping = @embedFile("../examples/escaping.zx");
    const zig_example_escaping = @embedFile("../examples/escaping.zig");
    const html_page_escaping = @import("../examples/escaping.zig").RawHtml(allocator);
    html_page_escaping.render(&aw_escaping.writer) catch unreachable;
    const html_example_escaping = allocator.dupe(u8, aw_escaping.written()) catch unreachable;

    // CSR example
    var aw_csr: std.io.Writer.Allocating = .init(allocator);
    const zx_example_csr = @embedFile("../examples/react.zx");
    const zig_example_csr = @embedFile("../examples/react.zig");
    const html_page_csr = @import("../examples/react.zig").ReactDemo(allocator);
    html_page_csr.render(&aw_csr.writer) catch unreachable;
    const html_example_csr = allocator.dupe(u8, aw_csr.written()) catch unreachable;

    // Importing example
    var aw_importing: std.io.Writer.Allocating = .init(allocator);
    const zx_example_importing = @embedFile("../examples/importing.zx");
    const zig_example_importing = @embedFile("../examples/importing.zig");
    const html_page_importing = @import("../examples/importing.zig").ImportDemo(allocator);
    html_page_importing.render(&aw_importing.writer) catch unreachable;
    const html_example_importing = allocator.dupe(u8, aw_importing.written()) catch unreachable;

    // Dynamic route example
    var aw_dynamic: std.io.Writer.Allocating = .init(allocator);
    const zx_example_dynamic = @embedFile("../examples/dynamic_route.zx");
    const zig_example_dynamic = @embedFile("../examples/dynamic_route.zig");
    const html_page_dynamic = @import("../examples/dynamic_route.zig").UserProfile(ctx);
    html_page_dynamic.render(&aw_dynamic.writer) catch unreachable;
    const html_example_dynamic = allocator.dupe(u8, aw_dynamic.written()) catch unreachable;

    // Fragment example
    var aw_fragment: std.io.Writer.Allocating = .init(allocator);
    const zx_example_fragment = @embedFile("../examples/fragment.zx");
    const zig_example_fragment = @embedFile("../examples/fragment.zig");
    const html_page_fragment = @import("../examples/fragment.zig").FragmentDemo(allocator);
    html_page_fragment.render(&aw_fragment.writer) catch unreachable;
    const html_example_fragment = allocator.dupe(u8, aw_fragment.written()) catch unreachable;

    // Children example
    var aw_children: std.io.Writer.Allocating = .init(allocator);
    const zx_example_children = @embedFile("../examples/children.zx");
    const zig_example_children = @embedFile("../examples/children.zig");
    const html_page_children = @import("../examples/children.zig").CardDemo(allocator);
    html_page_children.render(&aw_children.writer) catch unreachable;
    const html_example_children = allocator.dupe(u8, aw_children.written()) catch unreachable;

    // const setup_elapsed_ns = page_timer.read();
    // const setup_elapsed_ms = @as(f64, @floatFromInt(setup_elapsed_ns)) / @as(f64, @floatFromInt(std.time.ns_per_ms));
    // std.log.info("\x1b[1;36m[DOCS PAGE] Setup phase completed: {d:.3}ms\x1b[0m", .{setup_elapsed_ms});

    // Allocate files on heap to avoid stack lifetime issues
    const layout_files = blk: {
        const files = allocator.alloc(File, 2) catch unreachable;
        files[0] = .{ .filename = "layout.zx", .code = zx_example_layout };
        files[1] = .{ .filename = "page.zx", .code = zx_example_routing };
        break :blk files;
    };
    return (
        <div @allocator={allocator}>
            <Introduction />
            <section id="expressions" class="section">
                <h2>Expressions</h2>
                <p>Use curly braces <code>{expr_syntax}</code> to embed any Zig expression. Values are automatically formatted based on their type and HTML-escaped for safety.</p>
                <ExampleBlock id="expressions-example" zx_code={zx_example_expr} zig_code={zig_example_expr} html_code={html_example_expr} filename="expressions.zx" />

                <h3 id="expr-strings">Strings</h3>
                <p>String values (<code>[]const u8</code>) are displayed as text and automatically HTML-escaped to prevent XSS attacks. This is the safe default for displaying user input or any dynamic text content.</p>
                <CodeBlock code={expr_string_example} />

                <h3 id="expr-integers">Integers</h3>
                <p>Integer types (<code>i32</code>, <code>u64</code>, <code>comptime_int</code>, etc.) are formatted as decimal numbers. The special case <code>u8</code> is printed as a character if it's a printable ASCII character.</p>
                <CodeBlock code={expr_int_example} />

                <h3 id="expr-floats">Floats</h3>
                <p>Floating-point types (<code>f32</code>, <code>f64</code>, <code>comptime_float</code>) are formatted as decimal numbers.</p>
                <CodeBlock code={expr_float_example} />

                <h3 id="expr-booleans">Booleans</h3>
                <p>Boolean values are displayed as the literal strings "true" or "false".</p>
                <CodeBlock code={expr_bool_example} />

                <h3 id="expr-enums">Enums</h3>
                <p>Enum values are displayed as their tag name. This is useful for displaying status values, categories, or any enumerated type.</p>
                <CodeBlock code={expr_enum_example} />

                <h3 id="expr-optionals">Optionals</h3>
                <p>Optional values (<code>?T</code>) are automatically unwrapped and rendered if present. If the value is <code>null</code>, nothing is rendered. This makes it easy to conditionally display content.</p>
                <CodeBlock code={expr_optional_example} />

                <h3 id="expr-null">Null</h3>
                <p>The <code>null</code> value renders nothing, producing no output in the final HTML.</p>

                <h3 id="expr-components">Components</h3>
                <p>A <code>zx.Component</code> value is rendered directly. This allows you to embed components returned from functions or stored in variables.</p>
                <CodeBlock code={expr_component_example} />

                <h3 id="expr-component-arrays">Component Arrays</h3>
                <p>Arrays or slices of components (<code>[]zx.Component</code>) are rendered as a fragment containing all the components in sequence.</p>
                <CodeBlock code={expr_component_array_example} />
            </section>
            <section id="control-flow" class="section">
                <h2>Control Flow</h2>
                <p>ZX supports conditional rendering and iteration using familiar Zig control flow constructs. These expressions allow you to conditionally render components or iterate over collections to build dynamic UIs.</p>
                <h3 id="if-statements">If Statements</h3>
                <p>Use <code>if</code> expressions to conditionally render components based on boolean conditions. The<code>else</code> branch is optional and can render alternative content when the condition is false.</p>
                <ExampleBlock id="if" zx_code={zx_example_if} zig_code={zig_example_if} html_code={html_example_if} filename="conditional.zx" />
                <h3 id="switch-statements">Switch Statements</h3>
                <p>Use <code>switch</code> expressions to match against enum values or other types. Each case can return either a string literal or a component. Switch expressions are particularly useful for rendering different UI based on state or user roles.</p>
                <ExampleBlock id="switch" zx_code={zx_example_switch} zig_code={zig_example_switch} html_code={html_example_switch} filename="role_switch.zx" />
                <h3 id="for-loops">For Loops</h3>
                <p>Use <code>for</code> loops to iterate over arrays, slices, or strings and render a component for each item. The loop variable can be used within the component body to display item-specific content. This is ideal for rendering lists, tables, or any repeating UI patterns.</p>
                <ExampleBlock id="for" zx_code={zx_example_for} zig_code={zig_example_for} html_code={html_example_for} filename="user_list.zx" />
                <h3 id="while-loops">While Loops</h3>
                <p>Use <code>while</code> loops for conditional iteration with a continuation expression. The syntax follows Zig's while loop pattern: <code>{"while (condition) : (continue_expr) (body)"}</code>. This is useful for generating numbered sequences or iterating until a condition is met.</p>
                <ExampleBlock id="while" zx_code={zx_example_while} zig_code={zig_example_while} html_code={html_example_while} filename="counter.zx" />
                <h3 id="optional-capture">Optional Capture</h3>
                <p>Use payload capture syntax to unwrap optional values in <code>if</code> and <code>while</code> expressions:</p>
                <CodeBlock code={optional_capture_example} />
                <p>If the optional is <code>null</code>, the body is skipped (or the <code>else</code> branch runs if provided).</p>
                <h3 id="error-capture">Error Capture</h3>
                <p>Capture errors from error unions using <code>else |err|</code> syntax:</p>
                <CodeBlock code={error_capture_example} />
                <p>This works with both <code>if</code> and <code>while</code> expressions for handling fallible operations.</p>
            </section>
            <section id="components" class="section">
                <h2>Components</h2>
                <p>Components are reusable functions that return <code>zx.Component</code>. They allow you to encapsulate UI logic and create modular, maintainable code. Components can accept props (properties) to customize their behavior and appearance.</p>
                <h3>Component Function Signatures</h3>
                <p>Component functions can use one of several signatures depending on their needs:</p>
                <ul>
                    <li><strong>Allocator only:</strong><code>fn Component(allocator: zx.Allocator) zx.Component</code></li>
                    <li><strong>With props:</strong><code>fn Component(allocator: zx.Allocator, props: Props) zx.Component</code></li>
                    <li><strong>Context (children only):</strong><code>fn Component(ctx: *zx.ComponentContext) zx.Component</code></li>
                    <li><strong>Context with props:</strong><code>fn Component(ctx: *zx.ComponentCtx(Props)) zx.Component</code></li>
                </ul>
                <h3 id="component-context">ComponentContext</h3>
                <p>Use <code>zx.ComponentContext</code> when your component needs access to children but has no custom props:</p>
                <CodeBlock code={component_ctx_example} />
                <h3 id="component-ctx-props">ComponentCtx with Props</h3>
                <p>Use <code>zx.ComponentCtx(Props)</code> when you need both custom props and children access:</p>
                <CodeBlock code={component_ctx_props_example} />
                <p>The context provides <code>ctx.allocator</code>, <code>ctx.props</code>, and <code>ctx.children</code>.</p>
                <h3>Defining Components</h3>
                <p>To create a component, define a function that returns a <code>zx.Component</code>. The function must have an allocator as its first parameter. If your component needs configuration, add a props struct as the second parameter:</p>
                <ExampleBlock id="components" zx_code={zx_example_components} zig_code={zig_example_components} html_code={html_example_components} filename="button_demo.zx" />
                <h3>Props Coercion</h3>
                <p>ZX automatically coerces the attributes you pass to a component into the expected props struct. Missing required fields will result in a compile-time error, while fields with default values are optional. This provides type safety while keeping component usage flexible.</p>
            </section>
            <section id="routing" class="section">
                <h2>Routing</h2>
                <p>ZX provides a file-based routing system that maps URL paths to page components. Routes can be nested, and layouts can be applied hierarchically to wrap pages with common UI elements.</p>
                <h3 id="pages">Pages</h3>
                <p>Pages are the main content components for each route. A page function must:</p>
                <ul>
                    <li>Accept a <code>zx.PageContext</code> as its only parameter</li>
                    <li>Return a <code>zx.Component</code></li>
                    <li>Be exported as <code>pub fn Page</code></li>
                </ul>
                <ExampleBlock id="routing" zx_code={zx_example_routing} zig_code={zig_example_routing} html_code={html_example_routing} filename="home_page.zx" />
                <h3 id="layouts">Layouts</h3>
                <p>Layouts wrap pages with common UI elements like headers, footers, or navigation. A layout function must:</p>
                <ul>
                    <li>Accept a <code>zx.LayoutContext</code> as the first parameter</li>
                    <li>Accept a <code>zx.Component</code> (the page content) as the second parameter</li>
                    <li>Return a <code>zx.Component</code></li>
                    <li>Be exported as <code>pub fn Layout</code></li>
                </ul>
                <ExampleBlock id="layout" files={layout_files} zig_code={zig_example_layout} html_code={html_example_layout} />
                <h3>PageContext and LayoutContext</h3>
                <p>Both <code>PageContext</code> and <code>LayoutContext</code> provide access to:</p>
                <ul>
                    <li><code>request</code>: The HTTP request object with headers, query params, body, etc.</li>
                    <li><code>response</code>: The HTTP response object for setting headers and writing the response</li>
                    <li><code>allocator</code>: Global allocator for persistent allocations (freed manually)</li>
                    <li><code>arena</code>: Request-scoped allocator that's automatically freed after the request (recommended for most use cases)</li>
                </ul>
                <p>Use <code>ctx.arena</code> for temporary allocations that only need to persist during request processing. This is the recommended allocator for most page and component code.</p>
            </section>
            <section id="builtin-attributes" class="section">
                <h2>Builtin Attributes</h2>
                <p>ZX provides special builtin attributes that control component behavior and memory management. These attributes are prefixed with <code>@</code> to distinguish them from regular HTML attributes.</p>
                <h3 id="allocator">@allocator</h3>
                <p>The <code>@allocator</code> attribute is required to be passed to the topmost component. All child components will inherit the allocator from the parent component. It is available to all child components and expressions within that component tree.</p>
                <p><strong>Why is @allocator needed?</strong></p>
                <p>ZX components can allocate memory for various purposes:</p>
                <ul>
                    <li>Storing text content (which is HTML-escaped and allocated)</li>
                    <li>Copying child components arrays</li>
                    <li>Copying attribute arrays</li>
                    <li>Formatting expressions that allocate formatted strings</li>
                </ul>
                <p><strong>Usage:</strong></p>
                <ExampleBlock id="allocator" zx_code={zx_example_allocator} zig_code={zig_example_allocator} html_code={html_example_allocator} filename="allocator_demo.zx" />
                <p><strong>Best Practices:</strong></p>
                <ul>
                    <li>Always use <code>ctx.arena</code> in page components (it's automatically freed after the request)</li>
                    <li>Pass the allocator parameter to custom components and use it in the <code>@allocator</code> attribute</li>
                    <li>Set <code>@allocator</code> on the root element of each component that needs memory allocation</li>
                    <li>Child components inherit the allocator from their parent's component, so you don't need to pass it explicitly to every nested component</li>
                </ul>
                <h3 id="escaping">@escaping</h3>
                <p>The <code>@escaping</code> attribute controls how text content is escaped within an element. By default, all text is HTML-escaped to prevent XSS attacks.</p>
                <p><strong>Values:</strong></p>
                <ul>
                    <li><code>.html</code> - Standard HTML escaping (default behavior)</li>
                    <li><code>.none</code> - No escaping; outputs raw HTML. Use with caution for trusted content only.</li>
                </ul>
                <ExampleBlock id="escaping" zx_code={zx_example_escaping} zig_code={zig_example_escaping} html_code={html_example_escaping} filename="raw_html.zx" />
                <p><strong>Warning:</strong> Only use <code>@escaping={"{.none}"}</code> for content you trust completely. User-provided content should always use the default escaping.</p>
                <h3 id="rendering">@rendering</h3>
                <p>The <code>@rendering</code> attribute enables client-side rendering for interactive components.</p>
                <p><strong>Values:</strong></p>
                <ul>
                    <li><code>.react</code> - Client-side render with React (for imported React/TSX components)</li>
                    <li><code>.client</code> - Client-side render with Zig (compile component to WebAssembly)</li>
                </ul>
                <ExampleBlock id="react" zx_code={zx_example_csr} zig_code={zig_example_csr} html_code={html_example_csr} filename="react_demo.zx" />
            </section>
            <section id="attribute-syntax" class="section">
                <h2>Attribute Syntax</h2>
                <p>ZX provides convenient syntax for working with attributes beyond simple static values.</p>
                <h3 id="spread-attributes">Spread Attributes</h3>
                <p>Use <code>{"{..struct}"}</code> to spread all fields of a struct as attributes on an element. This is useful for passing groups of attributes or forwarding props:</p>
                <CodeBlock code={spread_attrs_example} />
                <p>Spread attributes can be combined with explicit attributes. Explicit attributes take precedence when there are conflicts.</p>
                <h3 id="shorthand-attributes">Shorthand Attributes</h3>
                <p>When the attribute name matches the variable name, use the shorthand syntax <code>{"{variable}"}</code>:</p>
                <CodeBlock code={shorthand_attrs_example} />
                <p>This is equivalent to writing <code>class={"{class}"}</code> but more concise.</p>
                <h3 id="template-attributes">Template Attributes</h3>
                <p>Use backticks (<code>`</code>) for string interpolation in attribute values. Embed expressions with <code>{"{expr}"}</code> inside the template:</p>
                <CodeBlock code={template_attrs_example} />
                <p>Template attributes are useful for building dynamic URLs, class names, or data attributes that combine static text with dynamic values.</p>
            </section>
            <section id="importing" class="section">
                <h2>Importing</h2>
                <p>ZX supports importing components and modules from various sources. You can import ZX components from other files, React/TSX components for client-side interactivity, and standard Zig modules.</p>
                <ExampleBlock id="importing" zx_code={zx_example_importing} zig_code={zig_example_importing} html_code={html_example_importing} filename="import_demo.zx" />
                <p>Use <code>@jsImport</code> for React/TSX components and the standard <code>@import</code> for ZX and Zig files.</p>
            </section>
            <section id="dynamic-routes" class="section">
                <h2>Dynamic Routes</h2>
                <p>ZX supports dynamic route segments using bracket notation in folder names.</p>
                <h3>Creating Dynamic Routes</h3>
                <p>Create a folder with brackets around the parameter name:</p>
                <ul>
                    <li><code>site/pages/user/[id]/page.zx</code> → <code>/user/:id</code></li>
                    <li><code>site/pages/blog/[slug]/page.zx</code> → <code>/blog/:slug</code></li>
                    <li><code>site/pages/[category]/[item]/page.zx</code> → <code>/:category/:item</code></li>
                </ul>
                <h3>Accessing Route and Query Parameters</h3>
                <p>Use <code>ctx.request.getParam("name")</code> to access dynamic route parameters and <code>ctx.request.query("name")</code> for query strings:</p>
                <ExampleBlock id="dynamic-route" zx_code={zx_example_dynamic} zig_code={zig_example_dynamic} html_code={html_example_dynamic} filename="user_profile.zx" />
                <p>Both methods return <code>?[]const u8</code>, so use <code>orelse</code> to provide a default value.</p>
            </section>
            <section id="fragments" class="section">
                <h2>Fragments</h2>
                <p>Fragments allow you to return multiple elements from a component without adding an extra wrapper element to the DOM. Use the empty tag syntax <code>{"<>...</>"}</code> to create a fragment:</p>
                <ExampleBlock id="fragment" zx_code={zx_example_fragment} zig_code={zig_example_fragment} html_code={html_example_fragment} filename="fragment_demo.zx" />
                <p>The fragment's children are rendered directly without any containing element.</p>
            </section>
            <section id="children-props" class="section">
                <h2>Children Props</h2>
                <p>Components can accept child elements through a <code>children</code> prop, enabling wrapper and container patterns. Any elements between the opening and closing tags are passed as the <code>children</code> prop:</p>
                <ExampleBlock id="children" zx_code={zx_example_children} zig_code={zig_example_children} html_code={html_example_children} filename="card_demo.zx" />
            </section>
            <section id="syntax" class="section">
                <h2>Syntax Features</h2>
                <p>ZX supports additional Zig syntax features within templates.</p>
                <h3 id="multiline-strings">Multiline Strings</h3>
                <p>Use Zig's multiline string syntax (<code>\\</code>) to embed formatted text blocks:</p>
                <CodeBlock code={multiline_string_example} />
                <p>Each line prefixed with <code>\\</code> is concatenated. This is useful for code snippets, preformatted text, or ASCII art.</p>
                <h3 id="comments">Comments</h3>
                <p>Single-line comments are supported within ZX templates:</p>
                <CodeBlock code={comments_example} />
                <p>Comments are stripped from the output and do not appear in the rendered HTML.</p>
            </section>
            <CachingSection />
            <PluginsSection />
            <CLISection />
            // <ExamplesSection />
        </div>
    );
}

const zx = @import("zx");
const std = @import("std");
const root = @import("root");
const util = @import("util.zig");

const Introduction = @import("../components/introduction.zig").Introduction;
const ExamplesSection = @import("../components/examples_section.zig").ExamplesSection;
const example_block = @import("../components/example_block.zig");
const ExampleBlock = example_block.ExampleBlock;
const File = example_block.File;
const CodeBlock = @import("../components/code_block.zig").CodeBlock;
const InstallCLI = @import("../components/install_guide.zx").InstallCLI;

fn PluginsSection(allocator: zx.Allocator) zx.Component {
    // Embedded snippet files for plugin examples
    const plugin_examples = @embedFile("../../assets/snippets/plugin_examples.zig");
    const zx_init_options = @embedFile("../../assets/snippets/ZxInitOptions.zig");

    // Extract specific line ranges from the embedded snippets
    const tailwind_full_example = util.extractLines(allocator, plugin_examples, &.{.{ 2, 29 }});
    const esbuild_full_example = util.extractLines(allocator, plugin_examples, &.{.{ 32, 56 }});
    const combined_example = util.extractLines(allocator, plugin_examples, &.{.{ 59, 70 }});
    const custom_plugin_example = util.extractLines(allocator, plugin_examples, &.{.{ 73, 107 }});
    const plugin_options_struct = util.extractLines(allocator, zx_init_options, &.{.{ 79, 107 }});

    return (
        <section id="plugins" class="section" @allocator={allocator}>
            <h2>Plugins</h2>
            <p>ZX provides a plugin system to extend the build process with additional tools. Plugins run as build steps and integrate seamlessly with <code>zig build</code>.</p>

            <h3 id="plugin-overview">Overview</h3>
            <p>Plugins are configured in your <code>build.zig</code> file and passed to <code>zx.init()</code>. Each plugin adds build steps that run before or after ZX transpilation, allowing you to process CSS, bundle JavaScript, or run other tools.</p>
            <p>ZX provides <strong>builtin plugins</strong> for common tasks, and you can also <strong>create custom plugins</strong> for your specific needs.</p>

            <h3 id="builtin-plugins">Builtin Plugins</h3>
            <p>ZX ships with the following builtin plugins available via <code>zx.plugins</code>:</p>
            <ul>
                <li><strong><code>zx.plugins.tailwind</code></strong> — Compile Tailwind CSS styles</li>
                <li><strong><code>zx.plugins.esbuild</code></strong> — Bundle TypeScript/JavaScript for client-side code</li>
            </ul>

            <h3 id="tailwind-plugin">Tailwind CSS Plugin</h3>
            <p>The <code>tailwind</code> builtin plugin compiles your CSS using the Tailwind CSS CLI. It automatically runs after ZX transpiles your pages.</p>

            <h4>Options</h4>
            <table class="options-table">
                <thead>
                    <tr>
                        <th>Option</th>
                        <th>Type</th>
                        <th>Default</th>
                        <th>Description</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td><code>bin</code></td>
                        <td><code>?LazyPath</code></td>
                        <td><code>node_modules/.bin/tailwindcss</code></td>
                        <td>Path to the Tailwind CLI binary</td>
                    </tr>
                    <tr>
                        <td><code>input</code></td>
                        <td><code>?LazyPath</code></td>
                        <td><code>site/assets/styles.css</code></td>
                        <td>Input CSS file with Tailwind directives</td>
                    </tr>
                    <tr>
                        <td><code>output</code></td>
                        <td><code>?LazyPath</code></td>
                        <td><code>{"{outdir}"}/assets/styles.css</code></td>
                        <td>Output path for compiled CSS</td>
                    </tr>
                    <tr>
                        <td><code>minify</code></td>
                        <td><code>bool</code></td>
                        <td><code>false</code></td>
                        <td>Optimize and minify the output</td>
                    </tr>
                    <tr>
                        <td><code>optimize</code></td>
                        <td><code>bool</code></td>
                        <td><code>false</code></td>
                        <td>Optimize output without minifying</td>
                    </tr>
                    <tr>
                        <td><code>cwd</code></td>
                        <td><code>?LazyPath</code></td>
                        <td><code>null</code></td>
                        <td>Working directory for Tailwind</td>
                    </tr>
                    <tr>
                        <td><code>map</code></td>
                        <td><code>bool</code></td>
                        <td><code>false</code></td>
                        <td>Generate a source map</td>
                    </tr>
                </tbody>
            </table>

            <h4>Example</h4>
            <CodeBlock code={tailwind_full_example} filename="build.zig" />

            <h3 id="esbuild-plugin">esbuild Plugin</h3>
            <p>The <code>esbuild</code> builtin plugin bundles TypeScript or JavaScript files for client-side code. It supports modern JavaScript features and can bundle dependencies.</p>

            <h4>Options</h4>
            <table class="options-table">
                <thead>
                    <tr>
                        <th>Option</th>
                        <th>Type</th>
                        <th>Default</th>
                        <th>Description</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td><code>bin</code></td>
                        <td><code>?LazyPath</code></td>
                        <td><code>node_modules/.bin/esbuild</code></td>
                        <td>Path to the esbuild binary</td>
                    </tr>
                    <tr>
                        <td><code>input</code></td>
                        <td><code>?LazyPath</code></td>
                        <td><code>site/main.ts</code></td>
                        <td>Entry point file</td>
                    </tr>
                    <tr>
                        <td><code>output</code></td>
                        <td><code>?LazyPath</code></td>
                        <td><code>{"{outdir}"}/assets/main.js</code></td>
                        <td>Output file path</td>
                    </tr>
                    <tr>
                        <td><code>bundle</code></td>
                        <td><code>bool</code></td>
                        <td><code>true</code></td>
                        <td>Bundle all dependencies</td>
                    </tr>
                    <tr>
                        <td><code>minify</code></td>
                        <td><code>?bool</code></td>
                        <td><code>true</code> in release</td>
                        <td>Minify the output</td>
                    </tr>
                    <tr>
                        <td><code>sourcemap</code></td>
                        <td><code>?enum</code></td>
                        <td><code>inline</code> in debug</td>
                        <td>Source map mode: <code>none</code>, <code>inline</code>, <code>external</code>, <code>linked</code>, <code>both</code></td>
                    </tr>
                    <tr>
                        <td><code>log_level</code></td>
                        <td><code>?enum</code></td>
                        <td><code>silent</code></td>
                        <td>Log level: <code>verbose</code>, <code>debug</code>, <code>info</code>, <code>warning</code>, <code>error</code>, <code>silent</code></td>
                    </tr>
                    <tr>
                        <td><code>format</code></td>
                        <td><code>?enum</code></td>
                        <td>inferred</td>
                        <td>Output format: <code>iife</code>, <code>cjs</code>, <code>esm</code></td>
                    </tr>
                    <tr>
                        <td><code>platform</code></td>
                        <td><code>?enum</code></td>
                        <td><code>browser</code></td>
                        <td>Target platform: <code>browser</code>, <code>node</code>, <code>neutral</code></td>
                    </tr>
                    <tr>
                        <td><code>target</code></td>
                        <td><code>?[]const u8</code></td>
                        <td><code>esnext</code></td>
                        <td>Environment target (e.g., <code>es2017</code>, <code>chrome58</code>)</td>
                    </tr>
                    <tr>
                        <td><code>splitting</code></td>
                        <td><code>bool</code></td>
                        <td><code>false</code></td>
                        <td>Enable code splitting (ESM only)</td>
                    </tr>
                    <tr>
                        <td><code>external</code></td>
                        <td><code>[]const []const u8</code></td>
                        <td><code>&.{"{}"}</code></td>
                        <td>Modules to exclude from bundle</td>
                    </tr>
                    <tr>
                        <td><code>define</code></td>
                        <td><code>[]const struct</code></td>
                        <td><code>&.{"{}"}</code></td>
                        <td>Custom substitutions (key-value pairs)</td>
                    </tr>
                </tbody>
            </table>

            <p><strong>Automatic defines:</strong> The esbuild plugin automatically sets <code>__DEV__</code> and <code>process.env.NODE_ENV</code> based on the build mode.</p>

            <h4>Example</h4>
            <CodeBlock code={esbuild_full_example} filename="build.zig" />

            <h3 id="combining-plugins">Combining Plugins</h3>
            <p>You can use multiple plugins together. They run in order after ZX transpilation:</p>
            <CodeBlock code={combined_example} filename="build.zig" />

            <h3 id="custom-plugins">Creating Custom Plugins</h3>
            <p>You can create your own plugins by returning a <code>zx.ZxInitOptions.PluginOptions</code> struct. This allows you to integrate any command-line tool into the ZX build process.</p>

            <h4>Plugin Structure</h4>
            <p>A plugin consists of a name and a list of steps. Each step specifies when to run (before or after transpilation) and what command to execute:</p>
            <CodeBlock code={plugin_options_struct} />

            <h4>Example: Custom Image Optimizer Plugin</h4>
            <p>Here's how to create a custom plugin that optimizes images during the build:</p>
            <CodeBlock code={custom_plugin_example} filename="build.zig" />

            <h4>Plugin Lifecycle</h4>
            <ul>
                <li><strong><code>before_transpile</code></strong> — Runs before ZX transpiles <code>.zx</code> files to Zig. Useful for preprocessing source files.</li>
                <li><strong><code>after_transpile</code></strong> — Runs after ZX transpilation. Useful for post-processing like CSS compilation, JS bundling, or asset optimization.</li>
            </ul>

            <h4>Using <code>{"{outdir}"}</code></h4>
            <p>In output paths, use <code>{"{outdir}"}</code> as a placeholder for the ZX output directory.</p>

            <div class="callout tip">
                <strong>Tip:</strong> Look at the builtin plugins (<code>tailwind.zig</code> and <code>esbuild.zig</code> in the ZX source) for examples of how to structure complex plugins with many options.
            </div>
        </section>
    );
}

fn CachingSection(allocator: zx.Allocator) zx.Component {
    // Component caching examples
    const component_caching_basic =
        \\// Cache for 10 seconds
        \\(<Header @caching="10s" />)
        \\
        \\// Cache for 5 minutes
        \\(<Sidebar @caching="5m" />)
        \\
        \\// Cache for 1 hour
        \\(<Footer @caching="1h" />)
        \\
        \\// Cache for 1 day
        \\(<StaticContent @caching="1d" />)
    ;

    const component_caching_key =
        \\// Cache with a custom key for manual invalidation
        \\(<UserProfile @caching="10m:user-profile" user={user} />)
        \\
        \\// Cache navigation with key
        \\(<Navigation @caching="1h:main-nav" />)
    ;

    const page_caching_example =
        \\pub fn Page(ctx: zx.PageContext) zx.Component {
        \\    return (
        \\        <div @allocator={ctx.arena}>
        \\            <h1>Cached Page</h1>
        \\            <p>This page is cached for 5 minutes.</p>
        \\        </div>
        \\    );
        \\}
        \\
        \\// Enable page-level caching
        \\pub const options = zx.PageOptions{
        \\    .caching = .{ .seconds = 300 }, // 5 minutes
        \\};
    ;

    const layout_caching_example =
        \\pub fn Layout(ctx: zx.LayoutContext, children: zx.Component) zx.Component {
        \\    return (
        \\        <html @allocator={ctx.arena}>
        \\            <body>
        \\                <Header />
        \\                {children}
        \\                <Footer />
        \\            </body>
        \\        </html>
        \\    );
        \\}
        \\
        \\// Cache the entire layout for 1 hour
        \\pub const options = zx.LayoutOptions{
        \\    .caching = .{ .seconds = 3600 },
        \\};
    ;

    const cache_invalidation_example =
        \\// Delete a specific cache entry by key
        \\_ = zx.cache.del("cmp:user-profile");
        \\
        \\// Delete all entries matching a prefix
        \\// Useful for invalidating related content
        \\_ = zx.cache.delPrefix("cmp:user");
    ;

    return (
        <section id="caching" class="section" @allocator={allocator}>
            <h2>Caching <span class="badge">Alpha</span></h2>
            <p>ZX provides built-in caching for components, pages, and layouts to improve performance. Cached content is stored in memory and served directly without re-rendering.</p>

            <h3 id="caching-overview">Overview</h3>
            <p>Caching can be applied at three levels:</p>
            <ul>
                <li><strong>Component caching</strong> — Cache individual components using the <code>@caching</code> attribute</li>
                <li><strong>Page caching</strong> — Cache entire pages using <code>PageOptions.caching</code></li>
                <li><strong>Layout caching</strong> — Cache layouts using <code>LayoutOptions.caching</code></li>
            </ul>

            <h3 id="caching-components">Component Caching</h3>
            <p>Use the <code>@caching</code> attribute on any component to cache its rendered HTML output. The syntax is <code>{"<duration>"}</code> or <code>{"<duration>:key"}</code>.</p>

            <h4>Time Units</h4>
            <table class="options-table">
                <thead>
                    <tr>
                        <th>Unit</th>
                        <th>Description</th>
                        <th>Example</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td><code>s</code></td>
                        <td>Seconds</td>
                        <td><code>"10s"</code> = 10 seconds</td>
                    </tr>
                    <tr>
                        <td><code>m</code></td>
                        <td>Minutes</td>
                        <td><code>"5m"</code> = 300 seconds</td>
                    </tr>
                    <tr>
                        <td><code>h</code></td>
                        <td>Hours</td>
                        <td><code>"2h"</code> = 7200 seconds</td>
                    </tr>
                    <tr>
                        <td><code>d</code></td>
                        <td>Days</td>
                        <td><code>"1d"</code> = 86400 seconds</td>
                    </tr>
                </tbody>
            </table>

            <h4>Basic Usage</h4>
            <CodeBlock code={component_caching_basic} />

            <h4>Custom Cache Keys</h4>
            <p>Add a custom key after the duration with a colon (<code>:</code>) separator. Keys are useful for manual cache invalidation:</p>
            <CodeBlock code={component_caching_key} />
            <p>The cache key is prefixed with <code>cmp:</code> internally, so <code>"10m:user-profile"</code> creates a key <code>cmp:user-profile</code>.</p>

            <h3 id="caching-pages">Page Caching</h3>
            <p>Enable page-level caching by exporting a <code>options</code> constant with caching settings:</p>
            <CodeBlock code={page_caching_example} filename="page.zx" />
            <p>Page caching stores the entire rendered response including headers. The server adds <code>ETag</code> and <code>Cache-Control</code> headers automatically.</p>

            <h3 id="caching-layouts">Layout Caching</h3>
            <p>Layouts can also be cached using <code>LayoutOptions</code>:</p>
            <CodeBlock code={layout_caching_example} filename="layout.zx" />
            <div class="callout note">
                <strong>Note:</strong> Layout caching caches the entire layout including children. Use with caution as it may cache dynamic page content unintentionally.
            </div>

            <h3 id="cache-invalidation">Cache Invalidation</h3>
            <p>Manually invalidate cache entries using <code>zx.cache</code> functions:</p>
            <CodeBlock code={cache_invalidation_example} />
            <p><strong>Available functions:</strong></p>
            <ul>
                <li><code>zx.cache.del(key)</code> — Delete a specific cache entry by exact key. Returns <code>true</code> if deleted.</li>
                <li><code>zx.cache.delPrefix(prefix)</code> — Delete all entries matching a prefix. Returns the count of deleted entries.</li>
                <li><code>zx.cache.get(key)</code> — Get cached HTML by key. Returns <code>?[]const u8</code>.</li>
            </ul>

            <h3 id="caching-best-practices">Best Practices</h3>
            <ul>
                <li><strong>Cache static content aggressively</strong> — Headers, footers, navigation, and other rarely-changing content benefit most from caching.</li>
                <li><strong>Use custom keys for related content</strong> — Group related cache entries with a common prefix for easy bulk invalidation.</li>
                <li><strong>Be careful with user-specific content</strong> — Don't cache components that display user-specific data without including user identity in the cache key.</li>
                <li><strong>Start with short TTLs</strong> — Begin with shorter cache durations and increase as you verify correctness.</li>
                <li><strong>Invalidate on data changes</strong> — Call <code>zx.cache.del()</code> or <code>zx.cache.delPrefix()</code> when underlying data changes.</li>
            </ul>

            <div class="callout tip">
                <strong>Performance tip:</strong> Component caching is most effective for expensive-to-render components with stable output, such as markdown content, syntax-highlighted code blocks, or complex nested structures.
            </div>
        </section>
    );
}

const CLIArg = struct {
    name: []const u8,
    description: []const u8,
};

const CLIFlag = struct {
    name: []const u8,
    description: []const u8,
};

const CLICommandInfo = struct {
    name: []const u8,
    id: []const u8,
    description: []const u8,
    usage: []const u8,
    badge: ?[]const u8 = null,
    arguments: ?[]const CLIArg = null,
    flags: ?[]const CLIFlag = null,
    note: ?[]const u8 = null,
};

const cli_commands = [_]CLICommandInfo{
    .{
        .name = "init",
        .id = "cli-init",
        .description = "Initialize a new ZX project. Creates all the necessary files and directory structure to get started with ZX.",
        .usage = "zx init [path] [flags]",
        .arguments = &[_]CLIArg{
            .{ .name = "[path]", .description = "Path to initialize the project in (default: current directory)" },
        },
        .flags = &[_]CLIFlag{
            .{ .name = "--template, -t <name>", .description = "Template to use (default: \"default\"). Options: default, react, wasm, react_wasm" },
            .{ .name = "--force, -f", .description = "Force initialization even if the directory is not empty" },
            .{ .name = "--existing", .description = "Initialize ZX in an existing project (only adds files that don't exist)" },
        },
        .note = "The command will warn if the directory is not empty. Use --force to override, or --existing to only add missing files.",
    },
    .{
        .name = "dev",
        .id = "cli-dev",
        .description = "Start the app in development mode with hot reloading. Watches for file changes and automatically rebuilds.",
        .usage = "zx dev [flags]",
        .flags = &[_]CLIFlag{
            .{ .name = "--binpath, -b <path>", .description = "Binpath of the app (default: auto-detected)" },
            .{ .name = "--build-args <args>", .description = "Additional arguments to pass to zig build" },
        },
    },
    .{
        .name = "serve",
        .id = "cli-serve",
        .description = "Serve the project for production. Builds and runs the executable.",
        .usage = "zx serve [flags]",
        .flags = &[_]CLIFlag{
            .{ .name = "--port, -p <number>", .description = "Port to run the server on (default: 3000)" },
        },
    },
    .{
        .name = "transpile",
        .id = "cli-transpile",
        .description = "Transpile .zx files to Zig source code. Useful for debugging or inspecting generated code.",
        .usage = "zx transpile <path> [flags]",
        .arguments = &[_]CLIArg{
            .{ .name = "<path>", .description = "Path to .zx file or directory (required)" },
        },
        .flags = &[_]CLIFlag{
            .{ .name = "--outdir, -o <directory>", .description = "Output directory (default: \".zx\")" },
        },
    },
    .{
        .name = "fmt",
        .id = "cli-fmt",
        .description = "Format ZX source code files according to ZX's formatting rules.",
        .usage = "zx fmt [path] [flags]",
        .badge = "Alpha",
        .arguments = &[_]CLIArg{
            .{ .name = "[path]", .description = "Path to .zx file or directory (optional, formats current directory if not specified)" },
        },
        .flags = &[_]CLIFlag{
            .{ .name = "--stdio", .description = "Read from stdin and write to stdout" },
            .{ .name = "--stdout", .description = "Write formatted output to stdout instead of modifying files" },
        },
    },
    .{
        .name = "export",
        .id = "cli-export",
        .description = "Generate static site assets. Builds your project and exports it for static hosting.",
        .usage = "zx export [flags]",
        .flags = &[_]CLIFlag{
            .{ .name = "--outdir, -o <directory>", .description = "Output directory (default: \"dist\")" },
            .{ .name = "--binpath, -b <path>", .description = "Binpath of the app executable (default: auto-detected)" },
        },
        .note = "Run zig build first to build the ZX executable before exporting.",
    },
    .{
        .name = "bundle",
        .id = "cli-bundle",
        .description = "Bundle the site into a deployable directory with the executable and assets.",
        .usage = "zx bundle [flags]",
        .flags = &[_]CLIFlag{
            .{ .name = "--outdir, -o <directory>", .description = "Output directory (default: \"bundle\")" },
            .{ .name = "--binpath, -b <path>", .description = "Binpath of the app executable (default: auto-detected)" },
        },
        .note = "Run zig build first to build the ZX executable before bundling.",
    },
    .{
        .name = "update",
        .id = "cli-update",
        .description = "Update the ZX dependency version in your project's build.zig.zon file.",
        .usage = "zx update [flags]",
        .flags = &[_]CLIFlag{
            .{ .name = "--version, -v <version>", .description = "Version to update to (default: \"latest\")" },
        },
    },
    .{
        .name = "upgrade",
        .id = "cli-upgrade",
        .description = "Upgrade the ZX CLI tool itself. Downloads and installs a new version of the CLI binary.",
        .usage = "zx upgrade [flags]",
        .flags = &[_]CLIFlag{
            .{ .name = "--version, -v <version>", .description = "Version to upgrade to (default: \"latest\")" },
        },
    },
    .{
        .name = "version",
        .id = "cli-version",
        .description = "Show the current version of the ZX CLI tool.",
        .usage = "zx version",
    },
};

fn CLISection(allocator: zx.Allocator) zx.Component {
    return (
        <section id="cli" class="section" @allocator={allocator}>
            <h2>Command Line Interface</h2>
            <p>ZX comes with a built-in CLI tool to help you create, develop, and deploy your projects.</p>

            <h3 id="cli-installation">Installation</h3>
            <p>Install the ZX CLI using one of the following methods:</p>
            <InstallCLI />

            {for (cli_commands) |cmd| (
                <CLICommand allocator={allocator} command={cmd} />
            )}
        </section>
    );
}

fn CLICommand(allocator: zx.Allocator, props: struct { command: CLICommandInfo }) zx.Component {
    const command = props.command;
    // Parse usage string into parts for syntax highlighting
    const usage = command.usage;
    var parts = std.ArrayList(struct { text: []const u8, class: []const u8 }).empty;
    defer parts.deinit(allocator);

    var iter = std.mem.tokenizeScalar(u8, usage, ' ');
    var first = true;
    while (iter.next()) |token| {
        const class_name = if (first) "function" else if (std.mem.startsWith(u8, token, "[") or std.mem.startsWith(u8, token, "<")) "variable" else "operator";
        parts.append(allocator, .{ .text = token, .class = class_name }) catch unreachable;
        first = false;
    }

    return (
        <div @allocator={allocator}>
            <h3 id={command.id}>
                {command.name}
                {if (command.badge) |badge| (
                    <span class="badge">{badge}</span>
                )}
            </h3>
            <p>{command.description}</p>

            <div class="install-box install-box-simple">
                <div class="install-box-content">
                    <div class="install-code">
                        <span class="install-prompt">$ </span>
                        {for (parts.items) |part| (
                            <span>
                                <span class={part.class}>{part.text} {" "}</span>
                            </span>
                        )}
                    </div>
                </div>
            </div>

            {if (command.arguments) |args| (
                <div>
                    <h4>Arguments</h4>
                    <ul>
                        {for (args) |arg| (
                            <li><code>{arg.name}</code> — {arg.description}</li>
                        )}
                    </ul>
                </div>
            )}

            {if (command.flags) |flags| (
                <div>
                    <h4>Flags</h4>
                    <ul>
                        {for (flags) |flag| (
                            <li><code>{flag.name}</code> — {flag.description}</li>
                        )}
                    </ul>
                </div>
            )}

            {if (command.note) |note| (
                <div class="callout">
                    <strong>Note:</strong> {note}
                </div>
            )}
        </div>
    );
}
