mirror of
https://github.com/ziex-dev/ziex.git
synced 2026-07-21 02:59:36 -06:00
265 lines
16 KiB
Plaintext
265 lines
16 KiB
Plaintext
pub fn Page(allocator: zx.Allocator) zx.Component {
|
|
// If example
|
|
var aw_if: std.io.Writer.Allocating = .init(allocator);
|
|
const zx_example_if = @embedFile("../../../pages/doc/example/if.zx");
|
|
const zig_example_if = @embedFile("../doc/example/if.zig");
|
|
const html_page_if = @import("../doc/example/if.zig").Page(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("../../../pages/doc/example/switch.zx");
|
|
const zig_example_switch = @embedFile("../doc/example/switch.zig");
|
|
const html_page_switch = @import("../doc/example/switch.zig").Page(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("../../../pages/doc/example/for.zx");
|
|
const zig_example_for = @embedFile("../doc/example/for.zig");
|
|
const html_page_for = @import("../doc/example/for.zig").Page(allocator);
|
|
html_page_for.render(&aw_for.writer) catch unreachable;
|
|
const html_example_for = allocator.dupe(u8, aw_for.written()) catch unreachable;
|
|
|
|
// Component expression example
|
|
var aw_component: std.io.Writer.Allocating = .init(allocator);
|
|
const zx_example_component = @embedFile("../../../pages/doc/example/component.zx");
|
|
const zig_example_component = @embedFile("../doc/example/component.zig");
|
|
const html_page_component = @import("../doc/example/component.zig").Page(allocator);
|
|
html_page_component.render(&aw_component.writer) catch unreachable;
|
|
const html_example_component = allocator.dupe(u8, aw_component.written()) catch unreachable;
|
|
|
|
// Text expression example
|
|
var aw_text: std.io.Writer.Allocating = .init(allocator);
|
|
const zx_example_text = @embedFile("../../../pages/doc/example/text.zx");
|
|
const zig_example_text = @embedFile("../doc/example/text.zig");
|
|
const html_page_text = @import("../doc/example/text.zig").Page(allocator);
|
|
html_page_text.render(&aw_text.writer) catch unreachable;
|
|
const html_example_text = allocator.dupe(u8, aw_text.written()) catch unreachable;
|
|
|
|
// Format expression example
|
|
var aw_format: std.io.Writer.Allocating = .init(allocator);
|
|
const zx_example_format = @embedFile("../../../pages/doc/example/format.zx");
|
|
const zig_example_format = @embedFile("../doc/example/format.zig");
|
|
const html_page_format = @import("../doc/example/format.zig").Page(allocator);
|
|
html_page_format.render(&aw_format.writer) catch unreachable;
|
|
const html_example_format = allocator.dupe(u8, aw_format.written()) catch unreachable;
|
|
|
|
const cmp_expr = "{(expression)}";
|
|
const txt_expr = "{expression}";
|
|
const fmt_expr = "{[expression:format]}";
|
|
|
|
var aw_icon_svg_base64: std.io.Writer.Allocating = .init(allocator);
|
|
std.base64.standard.Encoder.encodeWriter(&aw_icon_svg_base64.writer, @embedFile("../../public/zx-icon.svg")) catch unreachable;
|
|
const icon_href = std.fmt.allocPrint(allocator, "data:image/svg+xml;base64,{s}", .{aw_icon_svg_base64.written()}) catch unreachable;
|
|
|
|
return (
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>ZX Documentation - JSX-like Syntax for Zig</title>
|
|
<link rel="stylesheet" href="./assets/styles.css">
|
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/themes/prism.min.css" rel="stylesheet">
|
|
<link rel="icon" href={icon_href} type="image/svg+xml">
|
|
<style>
|
|
{[@embedFile("../../assets/doc.css"):s]}
|
|
</style>
|
|
</head>
|
|
|
|
<body>
|
|
|
|
<div class="container">
|
|
<nav class="sidebar">
|
|
<div class="nav-header">
|
|
<div class="nav-header-top">
|
|
<h1>ZX</h1>
|
|
</div>
|
|
<p class="nav-subtitle">HTML within Zig</p>
|
|
</div>
|
|
<ul class="nav-menu">
|
|
<li><a href="#introduction">Introduction</a></li>
|
|
<li class="nav-item-with-submenu">
|
|
<a href="#getting-started" class="nav-parent">Getting Started <span class="submenu-arrow">▼</span></a>
|
|
<ul class="nav-submenu">
|
|
<li><a href="#getting-started">Quick Start</a></li>
|
|
<li><a href="#editor-setup">Editor Setup</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#control-flow">Control Flow</a></li>
|
|
<li><a href="#expressions">Expressions</a></li>
|
|
<li><a href="#examples">Examples</a></li>
|
|
</ul>
|
|
</nav>
|
|
|
|
<main class="content">
|
|
<section id="introduction" class="section">
|
|
<div class="section-header">
|
|
<h2>Introduction</h2>
|
|
<div class="source-code-badge">
|
|
<a href="https://github.com/nurulhudaapon/zx" target="_blank" rel="noopener noreferrer" class="source-code-badge-link">
|
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
<path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"/>
|
|
</svg>
|
|
<span>View Source Code</span>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<p>ZX is a <strong>prototype</strong> Zig library for building web applications with JSX-like syntax. Write declarative UI
|
|
components using familiar JSX patterns, transpiled to efficient Zig code.</p>
|
|
<p>ZX combines the power and performance of Zig with the expressiveness of JSX, enabling you to build
|
|
fast, type-safe web applications. ZX uses <a href="https://github.com/karlseguin/http.zig" target="_blank" rel="noopener noreferrer">http.zig</a> to create high-performance HTTP servers, making it significantly faster than frameworks like Next.js. See benchmarks at <a href="https://zigweb.nuhu.dev" target="_blank" rel="noopener noreferrer">zigweb.nuhu.dev</a>.</p>
|
|
<p>Currently, ZX supports Server-Side Rendering (SSR) and Static Site Generation (SSG). Client-Side Rendering (CSR) may be implemented in the future by compiling Zig to WebAssembly and creating a bridge with JavaScript, once the prototype has proven the concept to be useful.</p>
|
|
</section>
|
|
|
|
<section id="getting-started" class="section">
|
|
<h2>Getting Started</h2>
|
|
<p>
|
|
To get started quickly, you can pull the
|
|
<a href="https://github.com/nurulhudaapon/zigx.nuhu.dev" target="_blank" rel="noopener noreferrer">
|
|
zigx.nuhu.dev
|
|
</a>
|
|
repository as a template and try it out yourself.
|
|
</p>
|
|
<p>
|
|
A full, step-by-step getting started guide is currently a work in progress and will be available here soon.
|
|
</p>
|
|
|
|
<h3 id="editor-setup">Editor Setup</h3>
|
|
<p>
|
|
Enhance your development experience with the official ZX extension for VSCode and Cursor. The extension provides syntax highlighting, code completion, and other helpful features for working with <code>.zx</code> files. Install it from <a href="https://open-vsx.org/extension/nurulhudaapon/zx" target="_blank" rel="noopener noreferrer">Open VSX</a>.
|
|
</p>
|
|
</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>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} />
|
|
|
|
<h3>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} />
|
|
|
|
<h3>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} />
|
|
</section>
|
|
|
|
<section id="expressions" class="section">
|
|
<h2>Expressions</h2>
|
|
<p>ZX provides different expression syntaxes for embedding dynamic content. Each syntax serves a specific purpose: rendering components, displaying text safely, or formatting values with custom format specifiers.</p>
|
|
|
|
<h3>Component Expressions</h3>
|
|
<p>Use <code>{cmp_expr}</code> to embed a component directly. The expression must evaluate to a <code>zx.Component</code> type. This is useful when you want to conditionally render or reuse components dynamically.</p>
|
|
<ExampleBlock id="component" zx_code={zx_example_component} zig_code={zig_example_component} html_code={html_example_component} />
|
|
|
|
<h3>Text Expressions</h3>
|
|
<p>Use <code>{txt_expr}</code> to embed text content. All text is automatically HTML-escaped to prevent XSS attacks. This is the safe way to display user input or dynamic text content.</p>
|
|
<ExampleBlock id="text" zx_code={zx_example_text} zig_code={zig_example_text} html_code={html_example_text} />
|
|
|
|
<h3>Format Expressions</h3>
|
|
<p>Use <code>{fmt_expr}</code> to format values with custom format specifiers. The format string follows Zig's standard format specifier syntax (e.g., <code>d</code> for decimal, <code>x</code> for hexadecimal). Unlike text expressions, format expressions are not HTML-escaped, making them suitable for numeric formatting and other non-HTML content.</p>
|
|
<ExampleBlock id="format" zx_code={zx_example_format} zig_code={zig_example_format} html_code={html_example_format} />
|
|
</section>
|
|
|
|
<section id="examples" class="section">
|
|
<h2>Examples</h2>
|
|
<ul>
|
|
<li>
|
|
<strong>This Documentation Site: </strong>
|
|
<a href="https://zx.nuhu.dev" target="_blank" rel="noopener noreferrer">Live</a> |
|
|
<a href="https://github.com/nurulhudaapon/zx/tree/main/site" target="_blank" rel="noopener noreferrer">Source</a>
|
|
</li>
|
|
<li>
|
|
<strong>A Portfolio Site with Blog: </strong>
|
|
<a href="https://zigx.nuhu.dev" target="_blank" rel="noopener noreferrer">Live</a> |
|
|
<a href="https://github.com/nurulhudaapon/zigx.nuhu.dev" target="_blank" rel="noopener noreferrer">Source</a>
|
|
</li>
|
|
</ul>
|
|
</section>
|
|
</main>
|
|
</div>
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/components/prism-core.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.30.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
|
<script type="module">
|
|
{[@embedFile("../../assets/doc.js"):s]}
|
|
</script>
|
|
</body>
|
|
</html>
|
|
);
|
|
}
|
|
|
|
|
|
const ExampleBlockProps = struct {
|
|
id: []const u8,
|
|
zx_code: []const u8,
|
|
zig_code: []const u8,
|
|
html_code: []const u8,
|
|
};
|
|
|
|
fn ExampleBlock(allocator: zx.Allocator, props: ExampleBlockProps) zx.Component {
|
|
// Extract and truncate ZX code
|
|
const zx_return_content = util.extractZxReturnContent(allocator, props.zx_code);
|
|
const truncated_zx_code = util.removeCommonIndentation(allocator, zx_return_content);
|
|
const escaped_full_zx = props.zx_code;
|
|
|
|
// Extract and truncate Zig code
|
|
const zig_return_content = util.extractZigReturnContent(allocator, props.zig_code);
|
|
const truncated_zig_code = util.removeCommonIndentation(allocator, zig_return_content);
|
|
const escaped_full_zig = props.zig_code;
|
|
|
|
const preview_id = std.fmt.allocPrint(allocator, "tab-{s}-preview", .{props.id}) catch unreachable;
|
|
const html_id = std.fmt.allocPrint(allocator, "tab-{s}-html", .{props.id}) catch unreachable;
|
|
const zig_id = std.fmt.allocPrint(allocator, "tab-{s}-zig", .{props.id}) catch unreachable;
|
|
const name_id = std.fmt.allocPrint(allocator, "tab-{s}", .{props.id}) catch unreachable;
|
|
const preview_content_id = std.fmt.allocPrint(allocator, "tab-preview-{s}", .{props.id}) catch unreachable;
|
|
const html_content_id = std.fmt.allocPrint(allocator, "tab-html-{s}", .{props.id}) catch unreachable;
|
|
const zig_content_id = std.fmt.allocPrint(allocator, "tab-zig-{s}", .{props.id}) catch unreachable;
|
|
const zx_code_id = std.fmt.allocPrint(allocator, "zx-code-{s}", .{props.id}) catch unreachable;
|
|
|
|
return (
|
|
<div class="code-example">
|
|
<div class="example-code">
|
|
<h4>ZX</h4>
|
|
<pre><code id={zx_code_id} class="language-jsx" contenteditable="true" spellcheck="false" data-full-content={escaped_full_zx} data-truncated-content={truncated_zx_code} title="Click to view full code">{truncated_zx_code}</code></pre>
|
|
</div>
|
|
<div class="example-code">
|
|
<input type="radio" id={preview_id} name={name_id} class="tab-radio" checked>
|
|
<input type="radio" id={html_id} name={name_id} class="tab-radio">
|
|
<input type="radio" id={zig_id} name={name_id} class="tab-radio">
|
|
<div class="pane-header">
|
|
<div class="tab-buttons">
|
|
<label for={preview_id} class="tab-btn">Preview</label>
|
|
<label for={html_id} class="tab-btn">HTML</label>
|
|
<label for={zig_id} class="tab-btn">Zig</label>
|
|
</div>
|
|
</div>
|
|
<div class="tab-content" id={preview_content_id}>
|
|
<div class="preview-wrapper">
|
|
<iframe class="preview-frame" srcdoc={props.html_code}></iframe>
|
|
</div>
|
|
</div>
|
|
<div class="tab-content" id={html_content_id}>
|
|
<div class="code-wrapper">
|
|
<pre><code class="language-markup">{props.html_code}</code></pre>
|
|
</div>
|
|
</div>
|
|
<div class="tab-content" id={zig_content_id}>
|
|
<div class="code-wrapper">
|
|
<pre><code class="language-zig" data-full-content={escaped_full_zig} data-truncated-content={truncated_zig_code}>{truncated_zig_code}</code></pre>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const zx = @import("zx");
|
|
const std = @import("std");
|
|
const util = @import("util.zig"); |