feat: add @TypeOf type hints for compiled templates
- Add TypeHint node type in parser for //- @TypeOf(field): type syntax
- Support scalar types (f32, i32, bool, etc.) and array/struct types
- Use helpers.appendValue() for non-string typed fields
- Filter out loop variable references from Data struct fields
- Preserve @TypeOf comments during comment stripping
Example usage:
//- @TypeOf(subtotal): f32
span $#{subtotal}
//- @TypeOf(items): []{name: []const u8, price: f32}
each item in items
h3 #{item.name}
This commit is contained in:
@@ -55,7 +55,7 @@ const CartItem = struct {
|
||||
|
||||
const Cart = struct {
|
||||
items: []const CartItem,
|
||||
subtotal: []const u8,
|
||||
subtotal: f32,
|
||||
shipping: []const u8,
|
||||
discount: ?[]const u8 = null,
|
||||
discountCode: ?[]const u8 = null,
|
||||
@@ -189,7 +189,7 @@ const sample_cart_items = [_]CartItem{
|
||||
|
||||
const sample_cart = Cart{
|
||||
.items = &sample_cart_items,
|
||||
.subtotal = "209.98",
|
||||
.subtotal = 209.98,
|
||||
.shipping = "0",
|
||||
.tax = "18.90",
|
||||
.total = "228.88",
|
||||
@@ -309,11 +309,17 @@ fn productDetail(app: *App, req: *httpz.Request, res: *httpz.Response) !void {
|
||||
fn cart(app: *App, _: *httpz.Request, res: *httpz.Response) !void {
|
||||
const html = if (USE_COMPILED_TEMPLATES) blk: {
|
||||
const templates = @import("templates");
|
||||
break :blk try templates.pages_cart.render(res.arena, .{
|
||||
.cartCount = "2",
|
||||
.subtotal = sample_cart.subtotal,
|
||||
.tax = sample_cart.tax,
|
||||
.total = sample_cart.total,
|
||||
const Data = templates.pages_cart.Data;
|
||||
break :blk try templates.pages_cart.render(res.arena, Data{
|
||||
.cartCount = "3",
|
||||
.cartItems = &.{
|
||||
.{ .variant = "Black", .name = "Wireless Headphones", .price = 79.99, .quantity = 1, .total = 79.99 },
|
||||
.{ .variant = "Silver", .name = "Laptop", .price = 500.00, .quantity = 1, .total = 500.00 },
|
||||
.{ .variant = "RGB", .name = "Mechanical Keyboard", .price = 129.99, .quantity = 1, .total = 129.99 },
|
||||
},
|
||||
.subtotal = 709.98,
|
||||
.tax = 63.90,
|
||||
.total = 773.88,
|
||||
});
|
||||
} else app.view.render(res.arena, "pages/cart", .{
|
||||
.title = "Shopping Cart",
|
||||
|
||||
@@ -14,17 +14,18 @@ block content
|
||||
.cart-layout
|
||||
.cart-main
|
||||
.cart-items
|
||||
//- @TypeOf(cartItems): []{name: []const u8, variant: []const u8, price: f32, quantity: u16, total: f32}
|
||||
each item in cartItems
|
||||
.cart-item
|
||||
.cart-item-info
|
||||
h3 #{name}
|
||||
p.text-muted #{variant}
|
||||
span.cart-item-price $#{price}
|
||||
h3 #{item.name}
|
||||
p.text-muted #{item.variant}
|
||||
span.cart-item-price $#{item.price}
|
||||
.cart-item-qty
|
||||
button.qty-btn -
|
||||
input.qty-input(type="text" value=quantity)
|
||||
input.qty-input(type="text" value=item.quantity)
|
||||
button.qty-btn +
|
||||
.cart-item-total $#{total}
|
||||
.cart-item-total $#{item.total}
|
||||
button.cart-item-remove x
|
||||
|
||||
.cart-actions
|
||||
@@ -34,14 +35,17 @@ block content
|
||||
h3 Order Summary
|
||||
.summary-row
|
||||
span Subtotal
|
||||
//- @TypeOf(subtotal): f32
|
||||
span $#{subtotal}
|
||||
.summary-row
|
||||
span Shipping
|
||||
span.text-success Free
|
||||
.summary-row
|
||||
span Tax
|
||||
//- @TypeOf(tax): f32
|
||||
span $#{tax}
|
||||
.summary-row.summary-total
|
||||
span Total
|
||||
//- @TypeOf(total): f32
|
||||
span $#{total}
|
||||
a.btn.btn-primary.btn-block(href="/checkout") Proceed to Checkout
|
||||
|
||||
Reference in New Issue
Block a user