{"shared_files":{"none_app":[{"path":"main.zig","content":"const std = @import(\"std\");\nconst zx = @import(\"zx\");\nconst pg = @import(\"Playground.zig\");\n\npub fn main() !void {\n    const io = zx.io();\n    const allocator = std.heap.page_allocator;\n    var aw = std.Io.Writer.Allocating.init(allocator);\n\n    const type_info = @typeInfo(pg);\n    const decls = type_info.@\"struct\".decl_names;\n\n    if (decls.len == 0) {\n        try std.Io.File.stdout().writeStreamingAll(io,\n            \\\\<pre>\n            \\\\No pub component found in Playground.zig\n            \\\\\n            \\\\Please define component,\n            \\\\with one of the following signatures:\n            \\\\\n            \\\\- pub fn (allocator: zx.Allocator) zx.Component;\n            \\\\- pub fn (ctx: *zx.ComponentContext) zx.Component;\n            \\\\</pre>\n        );\n        return;\n    }\n\n    inline for (decls) |decl_name| {\n        const component = try resolveComponent(allocator, io, decl_name);\n        try component.render(&aw.writer, .{});\n    }\n\n    try std.Io.File.stdout().writeStreamingAll(io, aw.written());\n}\n\nfn resolveComponent(allocator: zx.Allocator, io: std.Io, comptime field_name: []const u8) !zx.Component {\n    const Cmp = @field(pg, field_name);\n\n    switch (@typeInfo(@TypeOf(Cmp))) {\n        .@\"fn\" => |FnInfo| {\n            const param_count = FnInfo.param_types.len;\n            const FirstParam = FnInfo.param_types[0].?;\n\n            // fn(ctx: *zx.ComponentContext) zx.Component\n            if ((param_count == 1 and @typeInfo(FirstParam) == .pointer and\n                @hasField(@typeInfo(FirstParam).pointer.child, \"allocator\") and\n                @hasField(@typeInfo(FirstParam).pointer.child, \"children\")) or\n                (param_count == 1 and FirstParam == zx.Allocator) or\n                (param_count == 2 and FirstParam == zx.Allocator))\n            {\n                const cmp_fn = zx.client.ComponentMeta.init(Cmp);\n                return cmp_fn(allocator, \"Playground\", null);\n            }\n\n            // fn(ctx: zx.PageContext) zx.Component or fn(ctx: zx.PageContext) !zx.Component\n            if (param_count == 1 and FirstParam == zx.PageContext) {\n                const ctx = zx.PageContext{\n                    .request = .{\n                        .url = \"https://ziex.dev/playground\",\n                        .method = .GET,\n                        .pathname = \"playground\",\n                        .headers = .{},\n                        .arena = allocator,\n                    },\n                    .response = .{ .arena = allocator },\n                    .allocator = allocator,\n                    .arena = allocator,\n                    .io = io,\n                };\n                const result = Cmp(ctx);\n                if (@typeInfo(@TypeOf(result)) == .error_union) {\n                    return try result;\n                }\n                return result;\n            }\n\n            // fn(ctx: zx.LayoutContext, children: zx.Component) zx.Component\n            if (param_count == 2 and FirstParam == zx.LayoutContext and FnInfo.param_types[1].? == zx.Component) {\n                const ctx = zx.LayoutContext{\n                    .request = .{\n                        .url = \"https://ziex.dev/playground\",\n                        .method = .GET,\n                        .pathname = \"playground\",\n                        .headers = .{},\n                        .arena = allocator,\n                    },\n                    .response = .{ .arena = allocator },\n                    .allocator = allocator,\n                    .arena = allocator,\n                    .io = io,\n                };\n                return Cmp(ctx, .none);\n            }\n\n            @compileError(\"`Playground` must be `fn (*zx.ComponentContext) zx.Component` or `fn (zx.Allocator) zx.Component`\");\n        },\n\n        else => {\n            return .none;\n        },\n    }\n}\n"}],"app":[{"path":"app/main.zig","content":"const zx = @import(\"zx\");\n\npub fn main(init: zx.Init) !void {\n    var app = try zx.App.init(init, zx.io(), zx.allocator, .{}, {});\n    defer app.deinit();\n\n    try app.start();\n}\n\npub const std_options = zx.std_options;\n"}]},"templates":[{"name":"hello","description":"Hello","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn Playground(ctx: *zx.ComponentContext) zx.Component {\n    return (\n        <div @allocator={ctx.allocator}>\n            <style>{@embedFile(\"style.css\")}</style>\n\n            <h1>Ziex Playground</h1>\n            <p>Welcome to the minimal Ziex Playground demo.</p>\n            <p>Edit files and run your code!</p>\n\n            {for (\"Ziex\") |c| (<i>{c}</i>)}\n        </div>\n    );\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"style.css","content":"body {\n    background: #111;\n    color: #fff;\n    display: grid;\n    place-items: center;\n    height: 90vh;\n}"}]},{"name":"counter","description":"Counter","kind":"app","files":[{"path":"app/pages/layout.zx","content":"pub fn Layout(ctx: zx.LayoutContext, children: zx.Component) zx.Component {\n    return (\n        <html @allocator={ctx.arena} lang=\"en-US\">\n            <head>\n                <meta charset=\"UTF-8\" />\n                <title>Counter</title>\n            </head>\n            <body>\n                <nav>\n                    <a href=\"/\">Home</a>{\" · \"}\n                    <a href=\"/about\">About</a>{\" · \"}\n                    <a href=\"/api\">API</a>\n                </nav>\n                {children}\n            </body>\n        </html>\n    );\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"app/pages/page.zx","content":"pub fn Page(ctx: zx.PageContext) !zx.Component {\n    return (\n        <main @allocator={ctx.arena}>\n            <h2>Home</h2>\n            <Counter @rendering={.client} initial={0} />\n        </main>\n    );\n}\n\npub fn Counter(ctx: *zx.ComponentCtx(struct { initial: i32 })) ?zx.Component {\n    const count = ctx.state(i32, ctx.props.initial);\n    return (\n        <div @allocator={ctx.allocator}>\n            <button onclick={count.bind(increment)}>Count: {count}</button>\n        </div>\n    );\n}\n\nfn increment(x: i32) i32 {\n    return x + 1;\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"app/pages/about/page.zx","content":"pub fn Page(ctx: zx.PageContext) !zx.Component {\n    return (\n        <main @allocator={ctx.arena}>\n            <h2>About</h2>\n            <p>This is the about page.</p>\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"app/routes/api/route.zig","content":"pub fn GET(ctx: zx.RouteContext) !void {\n    try ctx.response.json(.{ .status = \"ok\" }, .{});\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"events","description":"Events","kind":"app","files":[{"path":"app/pages/layout.zx","content":"pub fn Layout(ctx: zx.LayoutContext, children: zx.Component) zx.Component {\n    return (\n        <html @allocator={ctx.arena} lang=\"en-US\">\n            <head>\n                <meta charset=\"UTF-8\" />\n                <title>Events</title>\n            </head>\n            <body>\n                <h1>Client events</h1>\n                {children}\n            </body>\n        </html>\n    );\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"app/pages/page.zx","content":"pub fn Page(ctx: zx.PageContext) !zx.Component {\n    return (\n        <main @allocator={ctx.arena}>\n            <p>Click and type;  open the console to see logs.</p>\n            <EventDemo @rendering={.client} />\n        </main>\n    );\n}\n\npub fn EventDemo(ctx: *zx.ComponentContext) zx.Component {\n    const clicks = ctx.state(i32, 0);\n    return (\n        <div @allocator={ctx.allocator}>\n            <button onclick={ctx.bind(onClick)}>Clicked {clicks}</button>\n            <input oninput={onInput} />\n            <form action={onSubmit}>\n                <input name=\"msg\"/>\n                <button type=\"submit\">Send</button>\n            </form>\n        </div>\n    );\n}\n\nfn onClick(e: *zx.client.Event.Stateful) void {\n    const c = e.state(i32);\n    c.set(c.get() + 1);\n    const pe = e.as(zx.client.events.PointerEvent, zx.allocator);\n    zx.log.info(\"click ({d},{d})\", .{ pe.client_x, pe.client_y });\n}\n\nfn onInput(e: zx.client.Event) void {\n    const v = e.value() orelse \"\";\n    zx.log.info(\"input: {s}\", .{v});\n}\n\nfn onSubmit(a: zx.client.Action) void {\n    const data = a.data(struct { msg: []const u8 });\n    zx.log.info(\"submit message: {s}\", .{data.msg});\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"greeting","description":"Greeting","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn HelloWorld(allocator: zx.Allocator) zx.Component {\n    return (\n        <main @allocator={allocator}>\n            <h1>Welcome to my app</h1>\n            <Greeting />\n        </main>\n    );\n}\n\nfn Greeting(allocator: zx.Allocator) zx.Component {\n    return (<p @allocator={allocator}>Hello, World!</p>);\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"markup","description":"Markup","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn AboutSection(allocator: zx.Allocator) zx.Component {\n    return (\n        <main @allocator={allocator}>\n            <h1>About</h1>\n            <p>Hello there.<br />How are you?</p>\n            <AboutCard />\n        </main>\n    );\n}\n\nfn AboutCard(allocator: zx.Allocator) zx.Component {\n    return (\n        <div @allocator={allocator} class=\"card\">\n            <h2>User Profile</h2>\n            <p>Welcome to the card component!</p>\n        </div>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"text-expr","description":"Text expression","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn UserGreeting(allocator: zx.Allocator) zx.Component {\n    const user_name = \"Alice\";\n    const greeting = \"Welcome back\";\n    return (\n        <main @allocator={allocator}>\n            <h1>{greeting}, {user_name}!</h1>\n            <p>Your profile is ready.</p>\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"format-expr","description":"Format expression","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn ProductInfo(allocator: zx.Allocator) zx.Component {\n    const price: f32 = 19.99;\n    const quantity: u32 = 3;\n    const is_available = true;\n    return (\n        <main @allocator={allocator}>\n            <p>Price: ${price}</p>\n            <p>Quantity: {quantity}</p>\n            <p>Available: {is_available}</p>\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"conditional","description":"Conditional","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn UserStatus(allocator: zx.Allocator) zx.Component {\n    const is_logged_in = true;\n    const is_admin = false;\n    return (\n        <main @allocator={allocator}>\n            {if (is_logged_in) (<p>Welcome back!</p>) else (<p>Please log in.</p>)}\n            {if (is_admin) (<button>Admin Panel</button>)}\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"switch","description":"Switch","kind":"none_app","files":[{"path":"Playground.zx","content":"const Role = enum { admin, member, guest };\npub fn RoleBadge(allocator: zx.Allocator) zx.Component {\n    const role: Role = .admin;\n    return (\n        <main @allocator={allocator}>\n            <span class=\"badge\">\n                {switch (role) {\n                    .admin => (<strong>Admin</strong>),\n                    .member => (\"Member\"),\n                    .guest => (\"Guest\"),\n                }}\n            </span>\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"list","description":"List","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn ProductList(allocator: zx.Allocator) zx.Component {\n    const products = [_][]const u8{ \"Apple\", \"Banana\", \"Orange\" };\n    return (\n        <main @allocator={allocator}>\n            <h2>Products</h2>\n            <ul>{for (products) |product| (<li>{product}</li>)}</ul>\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"props","description":"Props","kind":"none_app","files":[{"path":"Playground.zx","content":"const ButtonProps = struct {\n    title: []const u8 = \"Click Me\",\n    class: []const u8 = \"btn\",\n};\npub fn ButtonDemo(allocator: zx.Allocator) zx.Component {\n    return (\n        <main @allocator={allocator}>\n            <Button title=\"Submit\" class=\"primary\" />\n            <Button title=\"Cancel\" />\n            <Button />\n        </main>\n    );\n}\n\nfn Button(allocator: zx.Allocator, props: ButtonProps) zx.Component {\n    return (<button @allocator={allocator} class={props.class}>{props.title}</button>);\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"fragment","description":"Fragment","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn FragmentDemo(allocator: zx.Allocator) zx.Component {\n    return (\n        <main @allocator={allocator}>\n            <>\n                <h1>Welcome</h1>\n                <p>Multiple elements without a wrapper</p>\n            </>\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"children","description":"Children","kind":"none_app","files":[{"path":"Playground.zx","content":"const CardProps = struct { title: []const u8, children: zx.Component };\npub fn CardDemo(allocator: zx.Allocator) zx.Component {\n    return (\n        <main @allocator={allocator}>\n            <Card title=\"Welcome\">\n                <p>This content is passed as children.</p>\n                <button>Click me</button>\n            </Card>\n        </main>\n    );\n}\n\nfn Card(allocator: zx.Allocator, props: CardProps) zx.Component {\n    return (\n        <div @allocator={allocator} class=\"card\">\n            <h2>{props.title}</h2>\n            <div class=\"card-body\">{props.children}</div>\n        </div>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"dyn-attrs","description":"Dynamic attributes","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn DynamicAttrs(allocator: zx.Allocator) zx.Component {\n    const class_name = \"primary-btn\";\n    const user_id = \"user-123\";\n    const is_active = true;\n    return (\n        <main @allocator={allocator}>\n            <button class={class_name} id={user_id}>Submit</button>\n            <div class={if (is_active) \"active\" else \"inactive\"}>Dynamic class</div>\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"expressions","description":"Expressions","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn Expressions(allocator: zx.Allocator) zx.Component {\n    const name = \"Alice\";\n    const count: u32 = 42;\n    const price: f32 = 19.99;\n    const active = true;\n    return (\n        <main @allocator={allocator}>\n            <p>{name}</p>\n            <p>{count}</p>\n            <p>${price}</p>\n            <p>{active}</p>\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"component-fragment","description":"Component fragment","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn Fragment(\n    allocator: zx.Allocator,\n) zx.Component {\n    return (\n        <fragment @{allocator}>\n            <span>One</span>\n            <>\n                <p>Two</p><p>Three</p>\n            </>\n        </fragment>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"dyn-attr","description":"Dynamic attr","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn DynamicAttr(\n    allocator: zx.Allocator,\n) zx.Component {\n    const is_active = true;\n    const class = if (is_active) \"active\" else \"idle\";\n    const color = if (is_active) \"green\" else \"red\";\n    return (\n        <section @{allocator}>\n            <button class={class}>Go</button>\n            <button style=`color: {color};`>\n                Template String\n            </button>\n        </section>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"escaping","description":"Escaping","kind":"none_app","files":[{"path":"Playground.zx","content":"pub fn RawHtml(allocator: zx.Allocator) zx.Component {\n    const trusted = \"<strong>Trusted HTML</strong>\";\n    return (\n        <main @allocator={allocator}>\n            <div>{trusted}</div>\n            <div @escaping={.none}>{trusted}</div>\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"fs-routing","description":"File system routing","kind":"app","files":[{"path":"app/pages/layout.zx","content":"pub fn Layout(\n    ctx: zx.LayoutContext,\n    children: zx.Component,\n) zx.Component {\n    return (\n        <html @allocator={ctx.arena}>\n            <body>\n                {children}\n            </body>\n        </html>\n    );\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"app/pages/page.zx","content":"pub fn Page(\n    ctx: zx.PageContext,\n) zx.Component {\n    return (\n        <div @allocator={ctx.arena}>\n            <h1>Home</h1>\n        </div>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"learn-page","description":"Page + layout","kind":"app","files":[{"path":"app/pages/layout.zx","content":"pub fn Layout(ctx: zx.LayoutContext, children: zx.Component) zx.Component {\n    return (\n        <html @allocator={ctx.arena}>\n            <head><title>My App</title></head>\n            <body>\n                <nav><a href=\"/\">Home</a> <a href=\"/about\">About</a></nav>\n                <main>{children}</main>\n                <footer>© My App</footer>\n            </body>\n        </html>\n    );\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"app/pages/page.zx","content":"pub fn Page(ctx: zx.PageContext) zx.Component {\n    return (\n        <main @allocator={ctx.arena}>\n            <h1>About Us</h1>\n            <p>Welcome to our website!</p>\n            <p>Path: {ctx.request.pathname}</p>\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"csr","description":"Client-side rendering","kind":"app","files":[{"path":"app/pages/layout.zx","content":"pub fn Layout(ctx: zx.LayoutContext, children: zx.Component) zx.Component {\n    return (\n        <html @allocator={ctx.arena} lang=\"en-US\">\n            <head>\n                <meta charset=\"UTF-8\" />\n                <title>Playground</title>\n            </head>\n            <body>\n                {children}\n            </body>\n        </html>\n    );\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"app/pages/page.zx","content":"pub fn Page(ctx: zx.PageContext) !zx.Component {\n    return (\n        <main @allocator={ctx.arena}>\n            <Counter @rendering={.client} />\n        </main>\n    );\n}\npub fn Counter(ctx: *zx.ComponentCtx(void)) zx.Component {\n    const count = ctx.state(i32, 0);\n    return (\n        <div @allocator={ctx.allocator} class=\"counter\">\n            <button onclick={ctx.bind(increment)}>\n                Click Me: {count}\n            </button>\n        </div>\n    );\n}\nfn increment(e: *zx.client.Event.Stateful) void {\n    const count = e.state(i32);\n    count.set(count.get() + 1);\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"api-route","description":"API route","kind":"app","files":[{"path":"app/pages/layout.zx","content":"pub fn Layout(ctx: zx.LayoutContext, children: zx.Component) zx.Component {\n    return (\n        <html @allocator={ctx.arena}>\n            <head><title>My App</title></head>\n            <body>\n                <nav><a href=\"/\">Home</a> <a href=\"/about\">About</a></nav>\n                <main>{children}</main>\n                <footer>© My App</footer>\n            </body>\n        </html>\n    );\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"app/pages/page.zx","content":"pub fn Page(ctx: zx.PageContext) zx.Component {\n    return (\n        <main @allocator={ctx.arena}>\n            <h1>About Us</h1>\n            <p>Welcome to our website!</p>\n            <p>Path: {ctx.request.pathname}</p>\n        </main>\n    );\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"app/routes/api/route.zig","content":"pub fn GET(ctx: zx.RouteContext) !void {\n    try ctx.response.json(.{ .message = \"Hello World!\" }, .{});\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"onclick","description":"Onclick","kind":"app","files":[{"path":"app/pages/layout.zx","content":"pub fn Layout(ctx: zx.LayoutContext, children: zx.Component) zx.Component {\n    return (\n        <html @allocator={ctx.arena} lang=\"en-US\">\n            <head>\n                <meta charset=\"UTF-8\" />\n                <title>Playground</title>\n            </head>\n            <body>\n                {children}\n            </body>\n        </html>\n    );\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"app/pages/page.zx","content":"pub fn Page(ctx: zx.PageContext) !zx.Component {\n    return (<EventHandling @allocator={ctx.arena} @rendering={.client} />);\n}\npub fn Interactivity(allocator: zx.Allocator) zx.Component {\n    return (<EventHandling @{allocator} @rendering={.client} />);\n}\npub fn EventHandling(allocator: zx.Allocator) zx.Component {\n    return (\n        <main @allocator={allocator}>\n            <button onclick={handleClick}>Click me</button>\n            <input oninput={handleInput} />\n        </main>\n    );\n}\n\nfn handleClick(_: zx.client.Event) void {\n    zx.log.info(\"Clicked!\", .{});\n}\n\nfn handleInput(event: zx.client.Event) void {\n    const v = event.value() orelse \"\";\n    zx.log.info(\"Input: {s}\", .{v});\n}\n\nconst zx = @import(\"zx\");\n"}]},{"name":"state","description":"State management","kind":"app","files":[{"path":"app/pages/layout.zx","content":"pub fn Layout(ctx: zx.LayoutContext, children: zx.Component) zx.Component {\n    return (\n        <html @allocator={ctx.arena} lang=\"en-US\">\n            <head>\n                <meta charset=\"UTF-8\" />\n                <title>Playground</title>\n            </head>\n            <body>\n                {children}\n            </body>\n        </html>\n    );\n}\n\nconst zx = @import(\"zx\");\n"},{"path":"app/pages/page.zx","content":"pub fn Page(ctx: zx.PageContext) !zx.Component {\n    return (<StatePanel @allocator={ctx.arena} @rendering={.client} />);\n}\npub fn StateDemo(allocator: zx.Allocator) zx.Component {\n    return (<StatePanel @allocator={allocator} @rendering={.client} />);\n}\n\npub fn StatePanel(ctx: *zx.ComponentCtx(void)) zx.Component {\n    const count = ctx.state(i32, 0);\n    const title = ctx.state([]const u8, \"Hello\");\n    return (\n        <div @allocator={ctx.allocator}>\n            <h1>App State: {title.get()}</h1>\n            <p>Count: {count.get()}</p>\n            <button onclick={count.bind(incrementCount)}>Increment Count</button>\n        </div>\n    );\n}\n\nfn incrementCount(value: i32) i32 {\n    return value + 1;\n}\n\nconst zx = @import(\"zx\");\n"}]}]}