refactor: rename DTree to DValue

This commit is contained in:
udo
2026-06-12 11:05:52 +00:00
parent 941f5aea08
commit 7066da3cde
157 changed files with 1203 additions and 1074 deletions
@@ -6,7 +6,7 @@ COMPONENT(Request& context)
String subtitle = first(context.props["subtitle"].to_string(), "Choose your preferred authentication method");
String callback_url = first(context.props["callback_url"].to_string(), app_link("auth/callback", context));
DTree services = context.props["services"];
DValue services = context.props["services"];
if(services.get_type_name() != "array" || services["google"]["name"].to_string() == "")
{
services["google"]["name"] = "Google";
@@ -40,7 +40,7 @@ COMPONENT(Request& context)
<h2><?= title ?></h2>
<label><?= subtitle ?></label>
</div>
<? services.each([&](DTree service, String service_key) {
<? services.each([&](DValue service, String service_key) {
String client_id = context.props[service_key + "_client_id"].to_string();
String handler_name = ascii_safe_name(service_key);
String service_name = service["name"].to_string();
@@ -34,9 +34,9 @@ String data_format_bytes(String raw, bool disk = false)
return(String(buf) + " " + units[unit_index]);
}
DTree data_format_value(DTree value, DTree row, DTree column)
DValue data_format_value(DValue value, DValue row, DValue column)
{
DTree result;
DValue result;
String format = column["format"].to_string();
String raw = value.to_string();
String sort_value = raw;
@@ -98,7 +98,7 @@ COMPONENT:SUMMARY_METRICS(Request& context)
</div>
<? } ?>
<div class="dashboard-stat-grid">
<? context.props["items"].each([&](DTree item, String key) {
<? context.props["items"].each([&](DValue item, String key) {
String tone = first(item["tone"].to_string(), "info");
String href = item["href"].to_string();
String tag = href != "" ? "a" : "div";
@@ -162,7 +162,7 @@ COMPONENT:SORTABLE_TABLE(Request& context)
String subtitle = context.props["subtitle"].to_string();
String empty_label = first(context.props["empty_label"].to_string(), "No data available");
DTree init_options;
DValue init_options;
init_options["storageKey"] = first(context.props["storage_key"].to_string(), "starter.sort." + table_id);
if(context.props["sort"]["column"].to_string() != "")
{
@@ -182,7 +182,7 @@ COMPONENT:SORTABLE_TABLE(Request& context)
<table id="<?= table_id ?>" class="u-sortable-table">
<thead>
<tr>
<? context.props["columns"].each([&](DTree column, String key) {
<? context.props["columns"].each([&](DValue column, String key) {
String align = first(column["align"].to_string(), "left");
bool sortable = column["sortable"].to_string() == "" || column["sortable"].to_string() == "1";
?><th scope="col" class="align-<?= align ?>"<?= sortable ? "" : " data-sortable=\"false\"" ?>><?= first(column["label"].to_string(), column["key"].to_string(), "Column") ?></th><?
@@ -193,13 +193,13 @@ COMPONENT:SORTABLE_TABLE(Request& context)
<? if(context.props["rows"].get_type_name() != "array" || context.props["rows"]["0"].get_type_name() != "array") { ?>
<tr data-empty-row="1"><td colspan="<?= context.props["columns"]._map.size() == 0 ? "1" : std::to_string(context.props["columns"]._map.size()) ?>" class="muted"><?= empty_label ?></td></tr>
<? } ?>
<? context.props["rows"].each([&](DTree row, String key) {
<? context.props["rows"].each([&](DValue row, String key) {
if(row.get_type_name() != "array")
return;
?><tr><?
context.props["columns"].each([&](DTree column, String ckey) {
context.props["columns"].each([&](DValue column, String ckey) {
String col_key = column["key"].to_string();
DTree formatted = data_format_value(row[col_key], row, column);
DValue formatted = data_format_value(row[col_key], row, column);
?><td class="align-<?= first(column["align"].to_string(), "left") ?>" data-sort-value="<?= formatted["sort"].to_string() ?>"><?= formatted["display"].to_string() ?></td><?
});
?></tr><?
@@ -221,7 +221,7 @@ COMPONENT:DATA_TABLE(Request& context)
{
String table_id = first(context.props["id"].to_string(), "data-grid-" + std::to_string((u64)time()));
DTree columns = context.props["columns"];
DValue columns = context.props["columns"];
if(columns.get_type_name() != "array")
columns.set_array();
bool has_explicit_columns = columns.is_list() &&
@@ -230,8 +230,8 @@ COMPONENT:DATA_TABLE(Request& context)
columns["0"]["field"].to_string() != "";
if(!has_explicit_columns && context.props["items"]["0"].get_type_name() == "array")
{
context.props["items"]["0"].each([&](DTree value, String key) {
DTree col;
context.props["items"]["0"].each([&](DValue value, String key) {
DValue col;
col["field"] = key;
col["headerName"] = key;
col["sortable"].set_bool(true);
@@ -242,30 +242,30 @@ COMPONENT:DATA_TABLE(Request& context)
}
if(!columns.is_list())
{
DTree normalized_columns;
DValue normalized_columns;
normalized_columns.set_array();
columns.each([&](DTree column, String key) {
columns.each([&](DValue column, String key) {
if(column.get_type_name() == "array")
normalized_columns.push(column);
});
columns = normalized_columns;
}
DTree row_data = context.props["items"];
DValue row_data = context.props["items"];
if(row_data.get_type_name() != "array")
row_data.set_array();
if(!row_data.is_list())
{
DTree normalized_rows;
DValue normalized_rows;
normalized_rows.set_array();
row_data.each([&](DTree row, String key) {
row_data.each([&](DValue row, String key) {
if(row.get_type_name() == "array")
normalized_rows.push(row);
});
row_data = normalized_rows;
}
DTree grid_options;
DValue grid_options;
grid_options["pagination"].set_bool(true);
grid_options["paginationPageSize"] = first(context.props["options"]["paginationPageSize"].to_string(), "20");
grid_options["paginationPageSizeSelector"].set_bool(false);
@@ -1,10 +1,10 @@
#load "../../lib/app.uce"
void marketing_default_features(DTree& features)
void marketing_default_features(DValue& features)
{
if(features.get_type_name() == "array" && features["0"]["title"].to_string() != "")
return;
DTree item;
DValue item;
item["icon"] = "⚡";
item["title"] = "Lightning Fast";
@@ -194,7 +194,7 @@ COMPONENT:HERO_SECTION(Request& context)
COMPONENT:FEATURES_GRID(Request& context)
{
DTree features = context.props["features"];
DValue features = context.props["features"];
marketing_default_features(features);
<>
@@ -204,7 +204,7 @@ COMPONENT:FEATURES_GRID(Request& context)
<p>Discover the powerful features that make development a breeze</p>
</div>
<div class="features-grid">
<? features.each([&](DTree feature, String key) {
<? features.each([&](DValue feature, String key) {
?><div class="feature-card">
<div class="feature-icon"><?: feature["icon"].to_string() ?></div>
<h3 class="feature-title"><?= feature["title"].to_string() ?></h3>
@@ -288,10 +288,10 @@ COMPONENT:FEATURES_GRID(Request& context)
COMPONENT:STATS_SECTION(Request& context)
{
DTree stats = context.props["stats"];
DValue stats = context.props["stats"];
if(stats.get_type_name() != "array" || stats["0"]["label"].to_string() == "")
{
DTree item;
DValue item;
item["number"] = "99.9%"; item["label"] = "Uptime"; stats.push(item); item.clear();
item["number"] = "500ms"; item["label"] = "Average Response"; stats.push(item); item.clear();
item["number"] = "50K+"; item["label"] = "Active Users"; stats.push(item); item.clear();
@@ -306,7 +306,7 @@ COMPONENT:STATS_SECTION(Request& context)
<p>Join thousands of developers who have chosen our framework</p>
</div>
<div class="stats-grid">
<? stats.each([&](DTree stat, String key) {
<? stats.each([&](DValue stat, String key) {
?><div class="stat-item">
<div class="stat-number"><?= stat["number"].to_string() ?></div>
<div class="stat-label"><?= stat["label"].to_string() ?></div>
@@ -364,10 +364,10 @@ COMPONENT:STATS_SECTION(Request& context)
COMPONENT:BRANDS_SHOWCASE(Request& context)
{
DTree logos = context.props["logos"];
DValue logos = context.props["logos"];
if(logos.get_type_name() != "array" || logos["0"]["name"].to_string() == "")
{
DTree item;
DValue item;
for(s32 i = 1; i <= 6; i++)
{
item["name"] = "Brand " + std::to_string(i);
@@ -383,7 +383,7 @@ COMPONENT:BRANDS_SHOWCASE(Request& context)
<div class="brands-container">
<h3 class="brands-title"><?= title ?></h3>
<div class="brands-grid">
<? logos.each([&](DTree logo, String key) {
<? logos.each([&](DValue logo, String key) {
?><div class="brand-item">
<img src="<?= logo["url"].to_string() ?>" alt="<?= logo["name"].to_string() ?>" />
</div><?
@@ -410,10 +410,10 @@ COMPONENT:BRANDS_SHOWCASE(Request& context)
COMPONENT:TESTIMONIALS(Request& context)
{
DTree testimonials = context.props["testimonials"];
DValue testimonials = context.props["testimonials"];
if(testimonials.get_type_name() != "array" || testimonials["0"]["name"].to_string() == "")
{
DTree item;
DValue item;
item["name"] = "Sarah Johnson"; item["role"] = "Senior Developer at TechCorp"; item["avatar"] = "img/cat01.jpg"; item["content"] = "This framework has revolutionized our development process."; item["rating"] = "5"; testimonials.push(item); item.clear();
item["name"] = "Michael Chen"; item["role"] = "CTO at StartupX"; item["avatar"] = "img/cat02.jpg"; item["content"] = "We switched from our legacy system and saw immediate improvements."; item["rating"] = "5"; testimonials.push(item); item.clear();
item["name"] = "Emily Rodriguez"; item["role"] = "Full Stack Developer"; item["avatar"] = "img/cat03.jpg"; item["content"] = "The documentation is excellent and the learning curve is gentle."; item["rating"] = "5"; testimonials.push(item);
@@ -427,7 +427,7 @@ COMPONENT:TESTIMONIALS(Request& context)
<p>Don't just take our word for it - hear from the community</p>
</div>
<div class="testimonials-grid">
<? testimonials.each([&](DTree testimonial, String key) {
<? testimonials.each([&](DValue testimonial, String key) {
?><div class="testimonial-card">
<div class="testimonial-content">
<div class="quote-icon">"</div>
@@ -473,11 +473,11 @@ COMPONENT:TESTIMONIALS(Request& context)
COMPONENT:PRICING_TABLE(Request& context)
{
DTree plans = context.props["plans"];
DValue plans = context.props["plans"];
if(plans.get_type_name() != "array" || plans["0"]["name"].to_string() == "")
{
DTree plan;
DTree feature;
DValue plan;
DValue feature;
plan["name"] = "Starter"; plan["price"] = "Free"; plan["period"] = ""; plan["description"] = "Perfect for small projects and learning"; plan["cta"] = "Start Free"; feature = "Up to 3 projects"; plan["features"].push(feature); feature = "Community support"; plan["features"].push(feature); feature = "Basic components"; plan["features"].push(feature); plans.push(plan); plan.clear();
plan["name"] = "Pro"; plan["price"] = "$24"; plan["period"] = "/mo"; plan["description"] = "For serious products and teams"; plan["cta"] = "Choose Pro"; plan["popular"].set_bool(true); feature = "Unlimited projects"; plan["features"].push(feature); feature = "Priority support"; plan["features"].push(feature); feature = "Advanced components"; plan["features"].push(feature); plans.push(plan); plan.clear();
@@ -492,7 +492,7 @@ COMPONENT:PRICING_TABLE(Request& context)
<p>Choose the plan that fits your product stage.</p>
</div>
<div class="pricing-grid">
<? plans.each([&](DTree plan, String key) {
<? plans.each([&](DValue plan, String key) {
bool popular = plan["popular"].to_string() != "";
?><div class="pricing-card<?= popular ? " popular" : "" ?>">
<? if(popular) { ?><div class="popular-badge">Most Popular</div><? } ?>
@@ -505,7 +505,7 @@ COMPONENT:PRICING_TABLE(Request& context)
<p class="plan-description"><?= plan["description"].to_string() ?></p>
</div>
<ul class="plan-features">
<? plan["features"].each([&](DTree feature, String feature_key) { ?><li><?= feature.to_string() ?></li><? }); ?>
<? plan["features"].each([&](DValue feature, String feature_key) { ?><li><?= feature.to_string() ?></li><? }); ?>
</ul>
<div class="plan-footer">
<button class="btn <?= popular ? "btn-primary" : "btn-outline" ?> btn-large plan-cta"><?= first(plan["cta"].to_string(), "Choose Plan") ?></button>
@@ -107,7 +107,7 @@ COMPONENT(Request& context)
<div id="theme-menu" class="theme-menu" hidden>
<div class="theme-menu-title">Available Themes</div>
<div class="theme-menu-list">
<? context.cfg.get_by_path("theme/options").each([&](DTree theme_info, String theme_key) {
<? context.cfg.get_by_path("theme/options").each([&](DValue theme_info, String theme_key) {
StringMap params;
params["theme"] = theme_key;
String href = app_link(route_path == "index" ? "" : route_path, params, context);
@@ -2,7 +2,7 @@
COMPONENT(Request& context)
{
DTree asset_props;
DValue asset_props;
asset_props["css"]["0"] = "themes/common/css/gauges.css";
asset_props["js"]["0"] = "components/gauges/common.js";
print(component("../theme/assets", asset_props, context));
@@ -11,7 +11,7 @@ COMPONENT(Request& context)
String title = context.props["title"].to_string();
String subtitle = context.props["subtitle"].to_string();
String style = context.props["style"].to_string();
DTree scale = context.props["scale"];
DValue scale = context.props["scale"];
<>
<div class="arcgauge-set" id="<?= gauge_attr_id(gauge_id) ?>" style="<?= style ?>">
@@ -22,9 +22,9 @@ COMPONENT(Request& context)
</div>
<? } ?>
<div class="arcgauge-grid">
<? context.props["items"].each([&](DTree item, String item_id_raw) {
DTree merged = scale;
item.each([&](DTree value, String key) { merged[key] = value; });
<? context.props["items"].each([&](DValue item, String item_id_raw) {
DValue merged = scale;
item.each([&](DValue value, String key) { merged[key] = value; });
String item_id = gauge_attr_id(item_id_raw);
f64 value = float_val(first(merged["value"].to_string(), "0"));
f64 max_value = float_val(first(merged["max"].to_string(), "100"));
@@ -21,10 +21,10 @@ String gauge_attr_id(String value)
return(ascii_safe_name(value));
}
String gauge_range_color(DTree ranges, f64 value)
String gauge_range_color(DValue ranges, f64 value)
{
String matched = "";
ranges.each([&](DTree range, String key) {
ranges.each([&](DValue range, String key) {
f64 from_value = float_val(first(range["from"].to_string(), "-999999999"));
f64 to_value = float_val(first(range["to"].to_string(), "999999999"));
if(value >= from_value && value <= to_value && matched == "")
@@ -2,7 +2,7 @@
COMPONENT(Request& context)
{
DTree asset_props;
DValue asset_props;
asset_props["css"]["0"] = "themes/common/css/gauges.css";
asset_props["js"]["0"] = "components/gauges/common.js";
print(component("../theme/assets", asset_props, context));
@@ -12,7 +12,7 @@ COMPONENT(Request& context)
String title = context.props["title"].to_string();
String subtitle = context.props["subtitle"].to_string();
f64 size = float_val(first(context.props["size"].to_string(), "200"));
DTree scale = context.props["scale"];
DValue scale = context.props["scale"];
f64 scale_angle_start = float_val(first(scale["angle_start"].to_string(), std::to_string(-gauge_pi())));
f64 scale_angle_end = float_val(first(scale["angle_end"].to_string(), "0"));
f64 img_height = float_val(first(context.props["img_height"].to_string(), std::to_string(size * std::max(cos(scale_angle_start), cos(scale_angle_end)))));
@@ -26,9 +26,9 @@ COMPONENT(Request& context)
</div>
<? } ?>
<div class="needlegauge-grid">
<? context.props["items"].each([&](DTree item, String item_id_raw) {
DTree merged = scale;
item.each([&](DTree value, String key) { merged[key] = value; });
<? context.props["items"].each([&](DValue item, String item_id_raw) {
DValue merged = scale;
item.each([&](DValue value, String key) { merged[key] = value; });
String item_id = gauge_attr_id(item_id_raw);
String label = first(merged["label"].to_string(), item_id_raw);
String tooltip = merged["tooltip"].to_string();
@@ -85,7 +85,7 @@ COMPONENT(Request& context)
String segments_html = "";
if(merged["color"].get_type_name() == "array")
{
merged["color"].each([&](DTree range, String key) {
merged["color"].each([&](DValue range, String key) {
f64 range_from = std::max(float_val(first(range["from"].to_string(), std::to_string(min_value))), min_value);
f64 range_to = std::min(float_val(first(range["to"].to_string(), std::to_string(max_value))), max_value);
f64 angle_from = angle_start + ((range_from - min_value) / vrange) * (angle_end - angle_start);
@@ -2,7 +2,7 @@
COMPONENT(Request& context)
{
DTree asset_props;
DValue asset_props;
asset_props["css"]["0"] = "themes/common/css/gauges.css";
asset_props["js"]["0"] = "components/gauges/common.js";
print(component("../theme/assets", asset_props, context));
@@ -17,8 +17,8 @@ COMPONENT(Request& context)
String subtitle = context.props["subtitle"].to_string();
String layout = first(context.props["layout"].to_string(), "horizontal");
String bar_color_default = context.props["bar-color"].to_string();
DTree scale = context.props["scale"];
DTree markers = context.props["markers"];
DValue scale = context.props["scale"];
DValue markers = context.props["markers"];
StringList default_palette;
default_palette.push_back("var(--success, #10b981)");
@@ -37,9 +37,9 @@ COMPONENT(Request& context)
<? } ?>
<? if(layout == "horizontal") { ?>
<div class="progressbar-grid progressbar-grid-horizontal">
<? context.props["items"].each([&](DTree bar, String bar_id) {
DTree merged = scale;
bar.each([&](DTree item, String key) { merged[key] = item; });
<? context.props["items"].each([&](DValue bar, String bar_id) {
DValue merged = scale;
bar.each([&](DValue item, String key) { merged[key] = item; });
String item_id = gauge_attr_id(bar_id);
String merged_item_style = item_style;
if(merged["style"].to_string() != "")
@@ -73,7 +73,7 @@ COMPONENT(Request& context)
<div class="progressbar-background progressbar-background-horizontal">
<div class="progressbar-bar" id="<?= gauge_attr_id(gauge_id) ?>-<?= item_id ?>-bar"
style="background-color: <?= resolved_color ?>; <?= bar_style ?> opacity: <?= opacity ?>; width: <?= std::to_string(pct_value) ?>%;"></div>
<? markers.each([&](DTree marker, String marker_id) {
<? markers.each([&](DValue marker, String marker_id) {
f64 marker_value = float_val(first(marker["value"].to_string(), "0"));
f64 marker_pct = gauge_clamp_value(((marker_value - min_value) / vrange) * 100.0, 0.0, 100.0);
String marker_color = first(marker["color"].to_string(), "var(--primary-light)");
@@ -89,9 +89,9 @@ COMPONENT(Request& context)
</div>
<? } else { ?>
<div class="progressbar-grid progressbar-grid-vertical" style="--progressbar-height: <?= first(context.props["height"].to_string(), "240") ?>px;">
<? context.props["items"].each([&](DTree bar, String bar_id) {
DTree merged = scale;
bar.each([&](DTree item, String key) { merged[key] = item; });
<? context.props["items"].each([&](DValue bar, String bar_id) {
DValue merged = scale;
bar.each([&](DValue item, String key) { merged[key] = item; });
String item_id = gauge_attr_id(bar_id);
String merged_item_style = item_style;
if(merged["style"].to_string() != "")
@@ -122,7 +122,7 @@ COMPONENT(Request& context)
<div class="progressbar-background progressbar-background-vertical">
<div class="progressbar-bar" id="<?= gauge_attr_id(gauge_id) ?>-<?= item_id ?>-bar"
style="background-color: <?= resolved_color ?>; <?= bar_style ?> opacity: <?= opacity ?>; height: <?= std::to_string(pct_value) ?>%;"></div>
<? markers.each([&](DTree marker, String marker_id) {
<? markers.each([&](DValue marker, String marker_id) {
f64 marker_value = float_val(first(marker["value"].to_string(), "0"));
f64 marker_pct = gauge_clamp_value(((marker_value - min_value) / vrange) * 100.0, 0.0, 100.0);
String marker_color = first(marker["color"].to_string(), "var(--primary-light)");
@@ -3,7 +3,7 @@
COMPONENT(Request& context)
{
StarterUser users(context);
DTree user = users.current();
DValue user = users.current();
bool signed_in = user["email"].to_string() != "";
String theme_key = context.cfg.get_by_path("theme/key").to_string();
String wrapper_class = first(context.props["wrapper_class"].to_string(), theme_key == "localfirst" ? "admin-account-card" : "nav-account nav-menu");
@@ -18,7 +18,7 @@ void app_asset_tag_once(Request& context, String kind, String path)
}
}
void app_asset_tags(Request& context, String kind, DTree assets)
void app_asset_tags(Request& context, String kind, DValue assets)
{
String scalar = assets.to_string();
if(scalar != "")
@@ -26,7 +26,7 @@ void app_asset_tags(Request& context, String kind, DTree assets)
app_asset_tag_once(context, kind, scalar);
return;
}
assets.each([&](const DTree& item, String key) {
assets.each([&](const DValue& item, String key) {
app_asset_tag_once(context, kind, item.to_string());
});
}
@@ -6,7 +6,7 @@ COMPONENT(Request& context)
if(nav_class == "" && (context.cfg.get_by_path("theme/key").to_string() == "portal-dark" || context.cfg.get_by_path("theme/key").to_string() == "dark" || context.cfg.get_by_path("theme/key").to_string() == "retro-gaming"))
nav_class = "nav-shell";
DTree account_props;
DValue account_props;
if(context.props["account_wrapper_class"].to_string() != "")
account_props["wrapper_class"] = context.props["account_wrapper_class"];
if(context.props["links_wrapper_class"].to_string() != "")
@@ -18,7 +18,7 @@ COMPONENT(Request& context)
<nav<?: nav_class != "" ? " class=\"" + html_escape(nav_class) + "\"" : "" ?>>
<div class="nav-menu">
<a href="<?= app_link("", context) ?>"><?= context.cfg.get_by_path("site/name").to_string() ?></a>
<? context.cfg.get_by_path("menu").each([&](DTree menu_item, String menu_key) {
<? context.cfg.get_by_path("menu").each([&](DValue menu_item, String menu_key) {
if(menu_item["hidden"].to_string() == "1")
return;
String href = menu_item["external"].to_string() != "" ? "/" + menu_key : app_link(menu_key, context);
@@ -1,6 +1,6 @@
DTree get_config()
DValue get_config()
{
DTree config;
DValue config;
config["site"]["name"] = "UCE Starter";
config["site"]["default_page_title"] = "Home";
+7 -7
View File
@@ -1,19 +1,19 @@
#load "lib/app.uce"
DTree starter_router_result(String file, String param = "")
DValue starter_router_result(String file, String param = "")
{
DTree result;
DValue result;
result["file"] = file;
if(param != "")
result["param"] = param;
return(result);
}
DTree starter_router_resolve(Request& context)
DValue starter_router_resolve(Request& context)
{
String lpath = context.call["route"]["l_path"].to_string();
if(lpath == "")
return(DTree());
return(DValue());
String exact = "views/" + lpath + ".uce";
if(file_exists(exact))
@@ -34,14 +34,14 @@ DTree starter_router_resolve(Request& context)
return(starter_router_result(parent_index, param));
}
return(DTree());
return(DValue());
}
RENDER(Request& context)
{
app_init(context);
DTree resolved = starter_router_resolve(context);
DValue resolved = starter_router_resolve(context);
ob_start();
if(resolved["file"].to_string() != "")
@@ -52,7 +52,7 @@ RENDER(Request& context)
}
else
{
DTree notfound_props;
DValue notfound_props;
notfound_props["message"] = "The requested page does not exist.";
print(component("components/basic/notfound", notfound_props, context));
}
+3 -3
View File
@@ -45,7 +45,7 @@ void app_init(Request& context)
context.call["route"]["page"] = context.params["ROUTE_PAGE"];
context.call["route"]["valid"].set_bool(context.params["ROUTE_VALID"] != "0");
DTree config = get_config();
DValue config = get_config();
session_start();
String requested_theme = first(context.get["theme"], context.session["app_theme"], config["theme"]["key"].to_string());
if(config["theme"]["options"][requested_theme].get_type_name() != "array")
@@ -53,8 +53,8 @@ void app_init(Request& context)
if(context.get["theme"] != "")
context.session["app_theme"] = requested_theme;
DTree selected_theme = config["theme"]["options"][requested_theme];
selected_theme.each([&](DTree item, String key) {
DValue selected_theme = config["theme"]["options"][requested_theme];
selected_theme.each([&](DValue item, String key) {
config["theme"][key] = item;
});
config["theme"]["key"] = requested_theme;
+17 -17
View File
@@ -50,9 +50,9 @@ struct AppUser
return(hash);
}
static DTree read_json_file(String file_name)
static DValue read_json_file(String file_name)
{
DTree result;
DValue result;
if(!file_exists(file_name))
return(result);
String raw = trim(file_get_contents(file_name));
@@ -61,24 +61,24 @@ struct AppUser
return(json_decode(raw));
}
static bool write_json_file(String file_name, DTree data)
static bool write_json_file(String file_name, DValue data)
{
mkdir(dirname(file_name));
return(file_put_contents(file_name, json_encode(data)));
}
DTree load(String email)
DValue load(String email)
{
DTree user = read_json_file(file_name(email));
DValue user = read_json_file(file_name(email));
if(user.get_type_name() != "array")
return(DTree());
return(DValue());
user["id"] = normalize_email(email);
return(user);
}
DTree create(String email, String password)
DValue create(String email, String password)
{
DTree result;
DValue result;
email = normalize_email(email);
password = trim(password);
result["message"] = "";
@@ -95,7 +95,7 @@ struct AppUser
return(result);
}
DTree existing = load(email);
DValue existing = load(email);
if(existing.get_type_name() == "array" && existing["email"].to_string() != "")
{
result["message"] = "user_exists";
@@ -103,12 +103,12 @@ struct AppUser
}
String salt = gen_sha1(std::to_string((u64)time()) + ":" + std::to_string((u64)(time_precise() * 1000000.0)) + ":" + session_id_create()).substr(0, 24);
DTree user;
DValue user;
user["email"] = email;
user["salt"] = salt;
user["password_hash"] = password_hash(password, salt);
user["created"] = std::to_string((u64)time());
DTree role;
DValue role;
role = "user";
user["roles"].push(role);
@@ -120,14 +120,14 @@ struct AppUser
return(result);
}
DTree sign_in(String email, String password)
DValue sign_in(String email, String password)
{
DTree result;
DValue result;
result["result"].set_bool(false);
email = normalize_email(email);
password = trim(password);
DTree user = load(email);
DValue user = load(email);
if(user.get_type_name() != "array" || user["email"].to_string() == "")
{
result["message"] = "no_such_user";
@@ -161,7 +161,7 @@ struct AppUser
String user_id = context.session[session_key()];
if(user_id == "")
return(false);
DTree user = load(user_id);
DValue user = load(user_id);
if(user["email"].to_string() == "")
{
context.session.erase(session_key());
@@ -171,11 +171,11 @@ struct AppUser
return(true);
}
DTree current()
DValue current()
{
if(is_signed_in())
return(context.call["app"]["current_user"]);
return(DTree());
return(DValue());
}
void logout()
@@ -4,10 +4,10 @@ COMPONENT(Request& context)
{
String main_html = context.call["fragments"]["main"].to_string();
DTree nav_props;
DValue nav_props;
nav_props["account_wrapper_class"] = "nav-account nav-menu";
DTree footer_props;
DValue footer_props;
<>
<!doctype html>
@@ -4,7 +4,7 @@ COMPONENT(Request& context)
{
String main_html = context.call["fragments"]["main"].to_string();
DTree footer_props;
DValue footer_props;
<>
<!doctype html>
@@ -5,10 +5,10 @@ COMPONENT(Request& context)
String main_html = context.call["fragments"]["main"].to_string();
String current_path = context.call["route"]["l_path"].to_string();
DTree global_props;
DValue global_props;
global_props["cookie_consent"].set_bool(false);
DTree account_props;
DValue account_props;
account_props["wrapper_class"] = "admin-account-card";
account_props["links_wrapper_class"] = "admin-account-links";
account_props["name_class"] = "admin-account-name";
@@ -28,7 +28,7 @@ COMPONENT(Request& context)
<img class="admin-nav-logo-img" src="<?= app_asset_url("themes/localfirst/img/local_first_logo.png", context) ?>" alt="<?= context.cfg.get_by_path("site/name").to_string() ?>" />
</a>
</div>
<? context.cfg.get_by_path("menu").each([&](DTree menu_item, String menu_key) {
<? context.cfg.get_by_path("menu").each([&](DValue menu_item, String menu_key) {
if(menu_item["hidden"].to_string() == "1")
return;
bool active = menu_key != "" && (current_path == menu_key || current_path.rfind(menu_key + "/", 0) == 0);
@@ -4,10 +4,10 @@ COMPONENT(Request& context)
{
String main_html = context.call["fragments"]["main"].to_string();
DTree nav_props;
DValue nav_props;
nav_props["account_wrapper_class"] = "nav-account nav-menu";
DTree footer_props;
DValue footer_props;
<>
<!doctype html>
@@ -4,7 +4,7 @@ COMPONENT(Request& context)
{
String main_html = context.call["fragments"]["main"].to_string();
DTree footer_props;
DValue footer_props;
footer_props["inner_class"] = "footer-inner";
<>
@@ -4,10 +4,10 @@ COMPONENT(Request& context)
{
String main_html = context.call["fragments"]["main"].to_string();
DTree nav_props;
DValue nav_props;
nav_props["account_wrapper_class"] = "nav-account nav-menu";
DTree footer_props;
DValue footer_props;
<>
<!doctype html>
@@ -4,7 +4,7 @@ COMPONENT(Request& context)
{
context.call["app"]["page_title"] = "Login";
StarterUser users(context);
DTree result;
DValue result;
if(context.params["REQUEST_METHOD"] == "POST")
{
result = users.sign_in(context.post["email"], context.post["password"]);
@@ -9,9 +9,9 @@ COMPONENT(Request& context)
return;
}
context.call["app"]["page_title"] = "Profile";
DTree user = users.current();
DValue user = users.current();
String roles = "";
user["roles"].each([&](DTree role, String key) {
user["roles"].each([&](DValue role, String key) {
if(roles != "")
roles += ", ";
roles += role.to_string();
@@ -4,7 +4,7 @@ COMPONENT(Request& context)
{
context.call["app"]["page_title"] = "Register";
StarterUser users(context);
DTree result;
DValue result;
if(context.params["REQUEST_METHOD"] == "POST")
result = users.create(context.post["email"], context.post["password"]);
@@ -2,12 +2,12 @@
COMPONENT(Request& context)
{
DTree asset_props;
DValue asset_props;
asset_props["css"]["0"] = "views/marketing.css";
print(component("../../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Auth";
DTree props;
DValue props;
props["title"] = "Sign In to Your Account";
props["subtitle"] = "Choose your preferred authentication method to continue";
props["google_client_id"] = "YOUR_GOOGLE_CLIENT_ID";
@@ -4,8 +4,8 @@ COMPONENT(Request& context)
{
context.call["app"]["page_type"] = "json";
DTree response;
DTree body = json_decode(context.in);
DValue response;
DValue body = json_decode(context.in);
if(context.params["REQUEST_METHOD"] == "POST" && body["oauth_service"].to_string() != "" && body["oauth_state"].to_string() != "")
{
context.session["oauth_service"] = body["oauth_service"].to_string();
@@ -9,8 +9,8 @@ COMPONENT(Request& context)
{
context.call["app"]["page_title"] = "Dashboard";
DTree props;
DTree item;
DValue props;
DValue item;
item["label"] = "24h Requests"; item["value"] = "18,420"; item["meta"] = "+12.8% vs yesterday"; item["tone"] = "info"; props["items"].push(item); item.clear();
item["label"] = "Median Latency"; item["value"] = "182 ms"; item["meta"] = "stable over last 7 samples"; item["tone"] = "success"; props["items"].push(item); item.clear();
item["label"] = "Resident Memory"; item["value"] = "2.4 GB"; item["meta"] = "combined across workers"; item["tone"] = "warning"; props["items"].push(item); item.clear();
@@ -25,9 +25,9 @@ COMPONENT(Request& context)
print(component("../components/data/widgets:SUMMARY_METRICS", props, context));
props.clear();
DTree series;
DTree values;
DTree entry;
DValue series;
DValue values;
DValue entry;
entry["key"] = "requests"; entry["label"] = "Requests"; entry["color"] = "#60a5fa"; entry["axis"] = "left"; entry["format"] = "count";
values = "240"; entry["values"].push(values); values = "268"; entry["values"].push(values); values = "294"; entry["values"].push(values); values = "322"; entry["values"].push(values); values = "301"; entry["values"].push(values); values = "356"; entry["values"].push(values); values = "388"; entry["values"].push(values);
props["series"].push(entry); entry.clear();
@@ -53,14 +53,14 @@ COMPONENT(Request& context)
props["storage_key"] = "starter.dashboard.services";
props["sort"]["column"] = "2";
props["sort"]["direction"] = "desc";
DTree col;
DValue col;
col["key"] = "service"; col["label"] = "Service"; props["columns"].push(col); col.clear();
col["key"] = "uptime"; col["label"] = "Uptime"; props["columns"].push(col); col.clear();
col["key"] = "requests"; col["label"] = "Requests"; col["align"] = "right"; col["format"] = "number"; props["columns"].push(col); col.clear();
col["key"] = "memory"; col["label"] = "Memory"; col["align"] = "right"; col["format"] = "bytes"; props["columns"].push(col); col.clear();
col["key"] = "p95_latency"; col["label"] = "P95 Latency"; col["align"] = "right"; col["format"] = "duration-ms"; props["columns"].push(col); col.clear();
col["key"] = "healthy"; col["label"] = "Healthy"; col["align"] = "center"; col["format"] = "bool"; props["columns"].push(col);
DTree row;
DValue row;
row["service"] = "router"; row["uptime"] = "12 days"; row["requests"] = "142890"; row["memory"] = "402653184"; row["p95_latency"] = "148"; row["healthy"] = "true"; props["rows"].push(row); row.clear();
row["service"] = "queue-worker"; row["uptime"] = "8 days"; row["requests"] = "98214"; row["memory"] = "654311424"; row["p95_latency"] = "231"; row["healthy"] = "true"; props["rows"].push(row); row.clear();
row["service"] = "vector-index"; row["uptime"] = "5 days"; row["requests"] = "44892"; row["memory"] = "1241513984"; row["p95_latency"] = "312"; row["healthy"] = "true"; props["rows"].push(row); row.clear();
+1 -1
View File
@@ -2,7 +2,7 @@
COMPONENT(Request& context)
{
DTree asset_props;
DValue asset_props;
asset_props["css"]["0"] = "views/marketing.css";
print(component("../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Features";
+2 -2
View File
@@ -5,8 +5,8 @@ COMPONENT(Request& context)
context.call["app"]["page_title"] = "Gauges";
f64 pi = 3.14159265358979323846;
DTree props;
DTree item;
DValue props;
DValue item;
<>
<h1>Gauge Components Demo</h1>
+6 -6
View File
@@ -2,12 +2,12 @@
COMPONENT(Request& context)
{
DTree asset_props;
DValue asset_props;
asset_props["css"]["0"] = "views/marketing.css";
print(component("../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Home";
DTree props;
DValue props;
props["title"] = "Stunning Apps";
props["subtitle"] = "Experience the power of super bloated PHP development with our gigantic and truly unwieldy component-based framework. Seriously though, this page only serves as an example repository of different styles and blocks.";
@@ -17,7 +17,7 @@ COMPONENT(Request& context)
print(component("../components/example/marketing_blocks:FEATURES_GRID", context));
props.clear();
DTree stat;
DValue stat;
stat["number"] = "10K+"; stat["label"] = "Happy Vibe Coders"; props["stats"].push(stat); stat.clear();
stat["number"] = "<1s"; stat["label"] = "Page Load Time"; props["stats"].push(stat); stat.clear();
stat["number"] = "99.9%"; stat["label"] = "Uptime"; props["stats"].push(stat); stat.clear();
@@ -72,7 +72,7 @@ COMPONENT(Request& context)
<h2>Theme Families</h2>
<p>Compare the starters built-in theme families and jump to the live gallery.</p>
<div class="theme-grid">
<? context.cfg.get_by_path("theme/options").each([&](DTree theme, String key) {
<? context.cfg.get_by_path("theme/options").each([&](DValue theme, String key) {
if(key != "portal-light" && key != "portal-dark" && key != "localfirst")
return;
StringMap theme_params;
@@ -99,7 +99,7 @@ COMPONENT(Request& context)
props["secondary_text"] = "View GitHub";
print(component("../components/example/marketing_blocks:CTA_SECTION", props, context));
DTree island_props;
DValue island_props;
island_props["name"] = "StarterGuidelines";
island_props["id"] = "starter-guidelines-island";
island_props["props"]["route"] = context.call["route"]["l_path"].to_string();
@@ -120,7 +120,7 @@ COMPONENT(Request& context)
</>
props.clear();
DTree row;
DValue row;
row["name"] = "John Doe"; row["age"] = "25"; row["gender"] = "male"; row["department"] = "Engineering"; row["salary"] = "75000"; row["active"] = "true"; props["items"].push(row); row.clear();
row["name"] = "Jane Smith"; row["age"] = "30"; row["gender"] = "female"; row["department"] = "Design"; row["salary"] = "82000"; row["active"] = "true"; props["items"].push(row); row.clear();
row["name"] = "Bob Johnson"; row["age"] = "35"; row["gender"] = "male"; row["department"] = "Marketing"; row["salary"] = "68000"; row["active"] = "false"; props["items"].push(row); row.clear();
+2 -2
View File
@@ -2,7 +2,7 @@
COMPONENT(Request& context)
{
DTree asset_props;
DValue asset_props;
asset_props["css"]["0"] = "views/marketing.css";
print(component("../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Components";
@@ -51,7 +51,7 @@ COMPONENT(Request& context)
<div class="window-dot green"></div>
<span class="mono-text">views/index.uce</span>
</div>
<pre class="code-block"><code>DTree props;
<pre class="code-block"><code>DValue props;
props["title"] = "Stunning Apps";
&lt;&gt;&lt;?: component("example/marketing_blocks:HERO_SECTION", props, context) ?&gt;&lt;/&gt;</code></pre>
</div>
@@ -2,7 +2,7 @@
COMPONENT(Request& context)
{
DTree asset_props;
DValue asset_props;
asset_props["css"]["0"] = "views/themes.css";
print(component("../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Theme Preview";
+2 -2
View File
@@ -2,7 +2,7 @@
COMPONENT(Request& context)
{
DTree asset_props;
DValue asset_props;
asset_props["css"]["0"] = "views/themes.css";
print(component("../components/theme/assets", asset_props, context));
context.call["app"]["page_title"] = "Themes";
@@ -16,7 +16,7 @@ COMPONENT(Request& context)
<p>Open each theme preview directly to judge shell fit, typography, and token balance.</p>
</section>
<div class="theme-gallery-grid">
<? context.cfg.get_by_path("theme/options").each([&](DTree theme_info, String theme_key) {
<? context.cfg.get_by_path("theme/options").each([&](DValue theme_info, String theme_key) {
StringMap params;
params["theme"] = theme_key;
String preview_href = app_link("theme-preview", params, context);
@@ -25,35 +25,35 @@ COMPONENT(Request& context)
<div class="ws-demo-sidebar-copy"><p>This sidebar and mobile shell pattern was extracted from the AI portal app and normalized against starter theme tokens.</p></div>
</>
sidebar_body = ob_get_close();
DTree sidebar_note;
DValue sidebar_note;
sidebar_note["icon_class"] = "fas fa-circle-info";
sidebar_note["text"] = "Use workspace/overview, workspace/projects, or workspace/activity";
sidebar_body += component("../../components/workspace/primitives:LIST_STATE", sidebar_note, context);
DTree toolbar_props;
DValue toolbar_props;
toolbar_props["action_html"] = "<a class=\"ws-sidebar-action-btn\" href=\"" + app_link("workspace/overview", context) + "\"><i class=\"fas fa-grid-2\"></i><span>Open shell</span></a>";
toolbar_props["search_input_id"] = "workspace-demo-search";
toolbar_props["search_input_name"] = "workspace_demo_search";
toolbar_props["search_placeholder"] = "Search workspace sections";
String sidebar_top = component("../../components/workspace/primitives:SIDEBAR_TOOLBAR", toolbar_props, context);
DTree sidebar_props;
DValue sidebar_props;
sidebar_props["id"] = "workspace-demo-sidebar";
sidebar_props["top_html"] = sidebar_top;
sidebar_props["body_html"] = sidebar_body;
String sidebar = component("../../components/workspace/primitives:SIDEBAR_SHELL", sidebar_props, context);
DTree mobile_props;
DValue mobile_props;
mobile_props["button_id"] = "workspace-demo-toggle";
mobile_props["title"] = "Starter Workspace";
String mobile_bar = component("../../components/workspace/primitives:MOBILE_BAR", mobile_props, context);
DTree pill_props;
DValue pill_props;
pill_props["label"] = status_label;
pill_props["variant"] = status_variant;
String status_html = component("../../components/workspace/primitives:STATUS_PILL", pill_props, context);
DTree header_props;
DValue header_props;
header_props["title"] = title;
header_props["subtitle"] = subtitle;
header_props["actions_html"] = status_html;
@@ -81,10 +81,10 @@ COMPONENT(Request& context)
</>
detail_html = ob_get_close();
DTree section_head;
DValue section_head;
section_head["title"] = "Why this belongs in the starter";
String why_head = component("../../components/workspace/primitives:SECTION_HEAD", section_head, context);
DTree section_props;
DValue section_props;
section_props["header_html"] = why_head;
section_props["body_html"] = "<p class=\"ws-section-copy\">" + html_escape(description) + "</p>" + stats_html;
String main_body = component("../../components/workspace/primitives:SECTION", section_props, context);
@@ -99,7 +99,7 @@ COMPONENT(Request& context)
if(section == "activity")
{
DTree empty_props;
DValue empty_props;
empty_props["icon_class"] = "fas fa-clock-rotate-left";
empty_props["title"] = "No live stream wired yet";
empty_props["text"] = "The shell is generic. Add your own websocket, polling, or event-driven runtime behind it when a real product needs one.";
@@ -107,12 +107,12 @@ COMPONENT(Request& context)
main_body += component("../../components/workspace/primitives:EMPTY_STATE", empty_props, context);
}
DTree panel_props;
DValue panel_props;
panel_props["header_html"] = header;
panel_props["body_html"] = main_body;
String main = mobile_bar + component("../../components/workspace/primitives:PANEL", panel_props, context);
DTree app_props;
DValue app_props;
app_props["id"] = "workspace-demo-shell";
app_props["overlay_id"] = "workspace-demo-overlay";
app_props["sidebar_html"] = sidebar;