diff --git a/README.md b/README.md index 137c128..6a4ebd1 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ UCE is a PHP-inspired server-side runtime that lets you build web pages and hand - `.uce` pages compile to shared objects on demand - normal HTTP pages expose `RENDER(Request& context)` - WebSocket pages can additionally expose `WS(Request& context)` -- sub-rendering and components pass structured data through `context.call` +- sub-rendering and components pass structured data through `context.props` - nginx can forward normal `.uce` requests and ordinary `.ws.uce` page loads to the FastCGI socket, while real WebSocket upgrade requests for `.ws.uce` endpoints go to the built-in HTTP/WebSocket listener - the nginx-published application tree now lives under `site/` - you can include C++ code as much as you want, but only .uce files called via API functions and entry points will be pre-processed @@ -61,8 +61,10 @@ Useful related runtime patterns: - `unit_render(String file_name)` or `unit_render(String file_name, Request& context)` to invoke another page - `context.cfg` for request-local structured configuration -- `context.call` for invocation or message-local structured input +- `context.props` for invocation-local structured input such as component props - `context.connection` for broker-owned per-WebSocket-connection state shared across `WS(Request& context)` calls +- `context.in` for the current request body, including the current WebSocket message payload inside `WS(Request& context)` +- `context.params["WS_..."]` for direct WebSocket message metadata on the request parameter map - `context.params`, `context.get`, `context.post`, `context.cookies`, `context.session`, and `context.header` for request/response state - `context.set_status(code[, reason])` to set the HTTP response status @@ -81,7 +83,7 @@ Named component handlers are also supported: COMPONENT:BODY(Request& context) { <> -

+

} ``` @@ -117,7 +119,7 @@ UCE includes a native component layer built on top of ordinary `.uce` files: - `component_exists(name)` - `component_resolve(name)` -Component props are passed through `context.call`. +Component props are passed through `context.props`. Component names resolve: @@ -158,7 +160,9 @@ By default, the WebSocket scope is the current page file, so `ws_send()` queues Each live WebSocket connection now owns a broker-side `DTree` exposed to page code as `context.connection`. Mutations to that tree persist for the life of the socket and are visible on later `WS(Request& context)` calls for the same client. -`ws_message()` may contain either text or binary payload data. Use `ws_opcode()` / `ws_is_binary()` to inspect the current inbound message type. +The current inbound payload is available directly as `context.in`, and the runtime mirrors message metadata into `context.params` using keys such as `WS_CONNECTION_ID`, `WS_SCOPE`, `WS_CONNECTION_COUNT`, `WS_OPCODE`, `WS_MESSAGE_TYPE`, and `WS_DOCUMENT_URI`. + +`ws_message()` may still be used when you want the payload through a helper API. Use `ws_opcode()` / `ws_is_binary()` to inspect the current inbound message type. Set `binary = true` on `ws_send()` or `ws_send_to()` to queue a binary frame instead of a text frame. diff --git a/site/demo/components.uce b/site/demo/components.uce index 9de84c4..fd60e42 100644 --- a/site/demo/components.uce +++ b/site/demo/components.uce @@ -3,7 +3,7 @@ RENDER(Request& context) { DTree card_props; card_props["title"] = "Component Example"; - card_props["body"] = "This card body comes from context.call and is rendered through component()."; + card_props["body"] = "This card body comes from context.props and is rendered through component()."; DTree named_props; named_props["title"] = "Named Render Example"; diff --git a/site/demo/components/card.uce b/site/demo/components/card.uce index 4ffd73f..b8fe811 100644 --- a/site/demo/components/card.uce +++ b/site/demo/components/card.uce @@ -3,8 +3,8 @@ COMPONENT(Request& context) { <>
- - + +
} @@ -12,13 +12,13 @@ COMPONENT(Request& context) COMPONENT:TITLE(Request& context) { <> -

+

} COMPONENT:BODY(Request& context) { <> -

+

} diff --git a/site/demo/components/markdown/code_block.uce b/site/demo/components/markdown/code_block.uce index 15877f1..a3ddfd0 100644 --- a/site/demo/components/markdown/code_block.uce +++ b/site/demo/components/markdown/code_block.uce @@ -1,10 +1,10 @@ COMPONENT(Request& context) { - String lang = first(context.call["lang"].to_string(), "plain"); + String lang = first(context.props["lang"].to_string(), "plain"); <>

Code block:

-
+
} diff --git a/site/demo/components/markdown/warning.uce b/site/demo/components/markdown/warning.uce index dc0c6bd..eac7e5c 100644 --- a/site/demo/components/markdown/warning.uce +++ b/site/demo/components/markdown/warning.uce @@ -1,15 +1,15 @@ COMPONENT(Request& context) { String title = first( - context.call["node"]["attrs"]["title"].to_string(), - context.call["argument"].to_string(), + context.props["node"]["attrs"]["title"].to_string(), + context.props["argument"].to_string(), "Notice" ); <> } diff --git a/site/demo/index.uce b/site/demo/index.uce index e2a4b1d..ee3ae77 100644 --- a/site/demo/index.uce +++ b/site/demo/index.uce @@ -27,8 +27,6 @@ RENDER(Request& context) API Docs →
-
Coverage
-
Basics
diff --git a/site/demo/websockets.ws.uce b/site/demo/websockets.ws.uce index a44c5f2..de6dd46 100644 --- a/site/demo/websockets.ws.uce +++ b/site/demo/websockets.ws.uce @@ -13,9 +13,9 @@ DTree chat_event(Request& context, String type, String body) DTree event; event["type"] = type; event["body"] = body; - event["connection_id"] = ws_connection_id(); - event["scope"] = first(context.params["DOCUMENT_URI"], ws_scope()); - event["online"] = (f64)ws_connection_count(); + event["connection_id"] = context.params["WS_CONNECTION_ID"]; + event["scope"] = first(context.params["WS_DOCUMENT_URI"], context.params["DOCUMENT_URI"]); + event["online"] = float_val(first(context.params["WS_CONNECTION_COUNT"], "0")); event["at"] = time_format_utc("%H:%M:%S"); event["name"] = context.connection["name"].to_string(); event["message_count"] = context.connection["message_count"]; @@ -37,6 +37,7 @@ RENDER(Request& context)
Page scope: 
 Connected right now: 
 Status: Connecting...
+

This demo uses context.in for the current payload, context.params["WS_..."] for message metadata, and context.connection for per-client state.

@@ -152,13 +153,13 @@ WS(Request& context) if(ws_is_binary()) { ws_send_to( - ws_connection_id(), + context.params["WS_CONNECTION_ID"], json_encode(chat_event(context, "notice", "Binary messages are not handled by this demo")) ); return; } - DTree payload = json_decode(ws_message()); + DTree payload = json_decode(context.in); String type = clean_chat_field(payload["type"].to_string(), 24); String name = clean_chat_field(payload["name"].to_string(), 32); String body = clean_chat_field(payload["body"].to_string(), 500); @@ -190,6 +191,6 @@ WS(Request& context) if(type != "") { context.connection["last_type"] = type; - ws_send_to(ws_connection_id(), json_encode(chat_event(context, "notice", "Unknown message type: " + type))); + ws_send_to(context.params["WS_CONNECTION_ID"], json_encode(chat_event(context, "notice", "Unknown message type: " + type))); } } diff --git a/site/doc/pages/0_DTree.txt b/site/doc/pages/0_DTree.txt index 09929d7..8cc2e01 100644 --- a/site/doc/pages/0_DTree.txt +++ b/site/doc/pages/0_DTree.txt @@ -28,9 +28,8 @@ Map-shaped `DTree` values can also represent list-like data when their keys are You will encounter `DTree` throughout the runtime, especially in: -- `context.var` - `context.cfg` -- `context.call` +- `context.props` - `context.connection` - `json_decode()` results - `unit_call()` return values @@ -107,7 +106,7 @@ For non-map values, `each()` still invokes the callback once: - `key` is an empty string ```cpp -context.var["items"].each([&](DTree item, String key) { +context.connection["items"].each([&](DTree item, String key) { print(key, ": ", item.to_string(), "\n"); }); ``` @@ -119,7 +118,7 @@ String theme = context.cfg.get_by_path("theme/key").to_string(); u64 compiled_mtime = unit_info("test/hello.uce")["compiled_mtime"].to_u64(); -bool dark_mode = context.call["dark_mode"].to_bool(); +bool dark_mode = context.props["dark_mode"].to_bool(); if(DTree* user = payload.key("user")) { print(user->to_json()); diff --git a/site/doc/pages/0_Request.txt b/site/doc/pages/0_Request.txt index ed678c0..9b1f0fe 100644 --- a/site/doc/pages/0_Request.txt +++ b/site/doc/pages/0_Request.txt @@ -8,7 +8,7 @@ Request& context; >types :content -`Request& context` is the request-local state object passed into UCE handlers. It carries incoming request data, response state, runtime metadata, and helper trees such as `context.cfg`, `context.var`, and `context.call`. +`Request& context` is the request-local state object passed into UCE handlers. It carries incoming request data, response state, runtime metadata, and helper trees such as `context.cfg`, `context.props`, and `context.connection`. ## Core Fields @@ -20,9 +20,8 @@ Request& context; - `StringMap session`: current session data - `String session_id`: session cookie ID - `String session_name`: session cookie name -- `DTree var`: user-defined request-local data - `DTree cfg`: request-local configuration tree -- `DTree call`: invocation or message-local structured data +- `DTree call`: invocation-local structured data for helpers such as component and unit calls - `DTree connection`: broker-owned WebSocket connection state that persists across `WS(Request& context)` calls for the same socket - `std::vector uploaded_files`: files uploaded in the current request - `StringMap header`: headers to send back to the browser @@ -45,7 +44,9 @@ Request& context; ## Common Usage Notes - `context.cfg` is the usual place for structured configuration. Use `context.cfg.get_by_path("path/to/value")` for deep reads. -- `context.call` carries invocation data for component calls, unit calls, and WebSocket messages. +- `context.props` carries invocation data for component calls and unit calls. +- `context.in` carries the current request body, and for `WS(Request& context)` it is the current WebSocket message payload. +- `context.params["WS_..."]` exposes the current WebSocket message metadata directly on the request parameter map. - `context.connection` is only meaningful for WebSocket traffic and persists for the lifetime of the connection. `unit_render(String file_name, [Request& context])` invokes another UCE file using the current or supplied request context. diff --git a/site/doc/pages/1_COMPONENT.txt b/site/doc/pages/1_COMPONENT.txt index e191feb..0e22964 100644 --- a/site/doc/pages/1_COMPONENT.txt +++ b/site/doc/pages/1_COMPONENT.txt @@ -25,7 +25,7 @@ This keeps page rendering and component rendering separate: A file intended only for component reuse can define `COMPONENT()` without defining `RENDER()`. -Inside component handlers, props arrive through `context.call`. +Inside component handlers, props arrive through `context.props`. When you call `component(":NAME", props, context)` or `component_render(":NAME", props, context)`, the runtime resolves `:NAME` against the current `.uce` file instead of requiring the file name again. @@ -34,12 +34,12 @@ When you call `component(":NAME", props, context)` or `component_render(":NAME", ```cpp COMPONENT(Request& context) { - <>
+ <>
} COMPONENT:BODY(Request& context) { - <>

+ <>

} ``` diff --git a/site/doc/pages/1_RENDER.txt b/site/doc/pages/1_RENDER.txt index 5d12b69..4889ce3 100644 --- a/site/doc/pages/1_RENDER.txt +++ b/site/doc/pages/1_RENDER.txt @@ -18,9 +18,9 @@ The default page entrypoint is always the plain `RENDER(Request& context)` handl Reusable component handlers now live on `COMPONENT(Request& context)` and `COMPONENT:NAME(Request& context)`. The component helpers call those handlers, not `RENDER()`. -The request environment is passed explicitly through `context`, including params, cookies, post data, session state, headers, uploaded files, and the current `context.call` tree. +The request environment is passed explicitly through `context`, including params, cookies, post data, session state, headers, uploaded files, and the current `context.props` tree. -For a normal direct page request, `context.call` starts empty. +For a normal direct page request, `context.props` starts empty. If the page is invoked from another UCE file via `unit_render(file_name, context)`, the callee receives that same `context`. diff --git a/site/doc/pages/1_WS.txt b/site/doc/pages/1_WS.txt index e9667b0..92ba960 100644 --- a/site/doc/pages/1_WS.txt +++ b/site/doc/pages/1_WS.txt @@ -12,7 +12,7 @@ Defines the WebSocket message handler for the current `.ws.uce` page. The same page may expose both `RENDER(Request& context)` and `WS(Request& context)`. `RENDER(Request& context)` serves the initial HTTP response, while `WS(Request& context)` is called whenever a complete WebSocket message arrives for that page. -UCE reassembles fragmented messages before calling `WS(Request& context)`. Text and binary frames are both delivered. Use `context.call`, `context.connection`, `ws_opcode()`, and `ws_is_binary()` to inspect the current message. +UCE reassembles fragmented messages before calling `WS(Request& context)`. Text and binary frames are both delivered. The current payload is available directly on `context.in`, message metadata is mirrored into `context.params["WS_..."]`, and connection-local state lives on `context.connection`. ## Connection State @@ -20,13 +20,21 @@ UCE reassembles fragmented messages before calling `WS(Request& context)`. Text ## Message Data -The current message data is available in `context.call`: +The current message payload is available as: -- `context.call["message"]`: current message payload -- `context.call["connection_id"]`: sender connection ID -- `context.call["scope"]`: current endpoint scope -- `context.call["opcode"]`: WebSocket opcode of the current message -- `context.call["document_uri"]`: request URI of the current endpoint +- `context.in`: current WebSocket payload +- `context.params["WS_MESSAGE"]`: same payload mirrored into the parameter map + +The current message metadata is available as: + +- `context.params["WS_CONNECTION_ID"]`: sender connection ID +- `context.params["WS_SCOPE"]`: current endpoint scope +- `context.params["WS_CONNECTION_COUNT"]`: number of currently connected clients in that scope +- `context.params["WS_OPCODE"]`: WebSocket opcode of the current message +- `context.params["WS_MESSAGE_TYPE"]`: `TEXT` or `BINARY` +- `context.params["WS_DOCUMENT_URI"]`: request URI of the current endpoint + +Helper wrappers such as `ws_message()`, `ws_connection_id()`, `ws_scope()`, `ws_connection_count()`, `ws_opcode()`, and `ws_is_binary()` are still available when that reads better for the handler. ## Related Concepts diff --git a/site/doc/pages/3_C++ Preprocessor.txt b/site/doc/pages/3_C++ Preprocessor.txt index 58b3110..fa428e9 100644 --- a/site/doc/pages/3_C++ Preprocessor.txt +++ b/site/doc/pages/3_C++ Preprocessor.txt @@ -88,7 +88,7 @@ Literal output with trusted unescaped markup: ```cpp RENDER(Request& context) { - <>
+ <>
} ``` @@ -96,7 +96,7 @@ Roughly becomes: ```cpp print(R"(
)"); -print(component("components/card", context.call, context)); +print(component("components/card", context.props, context)); print(R"(
)"); ``` diff --git a/site/doc/pages/component.txt b/site/doc/pages/component.txt index 142805e..349a080 100644 --- a/site/doc/pages/component.txt +++ b/site/doc/pages/component.txt @@ -9,7 +9,7 @@ Renders another `.uce` file as a component and returns the captured output as a `component()` resolves the target file relative to the current page and also tries the `components/` prefix automatically, mirroring the shorthand used by the starter example project. -Component props are passed in `context.call`. +Component props are passed in `context.props`. Because `` HTML-escapes its value, embed component markup with ``, `print(component(...))`, or use `component_render(...)` for direct output. diff --git a/site/doc/pages/component_render.txt b/site/doc/pages/component_render.txt index 58356c6..dfc06ca 100644 --- a/site/doc/pages/component_render.txt +++ b/site/doc/pages/component_render.txt @@ -9,7 +9,7 @@ Renders another `.uce` file as a component and writes the result directly to the This is the direct-output counterpart to `component()`. -Component props are passed through `context.call`, and `name:COMPONENTFUNC` may be used to select a named handler exported by `COMPONENT:COMPONENTFUNC(Request& context)`. +Component props are passed through `context.props`, and `name:COMPONENTFUNC` may be used to select a named handler exported by `COMPONENT:COMPONENTFUNC(Request& context)`. When `name` starts with `:`, the runtime resolves that named handler against the current `.uce` file. diff --git a/site/doc/pages/markdown_to_html.txt b/site/doc/pages/markdown_to_html.txt index 8e22426..df6c9d3 100644 --- a/site/doc/pages/markdown_to_html.txt +++ b/site/doc/pages/markdown_to_html.txt @@ -70,22 +70,22 @@ options["components"]["node.directive"] = "components/markdown/directive"; If both an exact directive hook and a generic `node.directive` hook exist, the exact directive hook wins. -When a markdown hook component is called, its props arrive in `context.call`. +When a markdown hook component is called, its props arrive in `context.props`. Useful fields include: -- `context.call["hook"]` for the matched hook key such as `:::warning` or `node.code_block` -- `context.call["target"]` for the resolved component target name -- `context.call["default_html"]` for the renderer output without the hook -- `context.call["children_html"]` for already-rendered child HTML -- `context.call["node"]` for the full AST node -- `context.call["type"]` for the node type -- `context.call["name"]` for the directive name when applicable -- `context.call["argument"]` for directive remainder after the name -- `context.call["text"]` for source text used by nodes such as `code_block` -- `context.call["lang"]` for fenced code language -- `context.call["href"]`, `context.call["src"]`, and `context.call["title"]` -- `context.call["options"]` for the full markdown options tree +- `context.props["hook"]` for the matched hook key such as `:::warning` or `node.code_block` +- `context.props["target"]` for the resolved component target name +- `context.props["default_html"]` for the renderer output without the hook +- `context.props["children_html"]` for already-rendered child HTML +- `context.props["node"]` for the full AST node +- `context.props["type"]` for the node type +- `context.props["name"]` for the directive name when applicable +- `context.props["argument"]` for directive remainder after the name +- `context.props["text"]` for source text used by nodes such as `code_block` +- `context.props["lang"]` for fenced code language +- `context.props["href"]`, `context.props["src"]`, and `context.props["title"]` +- `context.props["options"]` for the full markdown options tree Directive blocks use this form: diff --git a/site/examples/uce-starter/components/auth/oauth-client.uce b/site/examples/uce-starter/components/auth/oauth-client.uce index 7439a78..557c1cc 100644 --- a/site/examples/uce-starter/components/auth/oauth-client.uce +++ b/site/examples/uce-starter/components/auth/oauth-client.uce @@ -2,11 +2,11 @@ COMPONENT(Request& context) { - String title = first(context.call["title"].to_string(), "Sign in with OAuth"); - String subtitle = first(context.call["subtitle"].to_string(), "Choose your preferred authentication method"); - String callback_url = first(context.call["callback_url"].to_string(), starter_link("auth/callback", context)); + String title = first(context.props["title"].to_string(), "Sign in with OAuth"); + String subtitle = first(context.props["subtitle"].to_string(), "Choose your preferred authentication method"); + String callback_url = first(context.props["callback_url"].to_string(), starter_link("auth/callback", context)); - DTree services = context.call["services"]; + DTree services = context.props["services"]; if(services.get_type_name() != "array" || services["google"]["name"].to_string() == "") { services["google"]["name"] = "Google"; @@ -41,7 +41,7 @@ COMPONENT(Request& context)
@@ -88,7 +88,7 @@ COMPONENT:SUMMARY_METRICS(Request& context)
-
@@ -139,7 +139,7 @@ COMPONENT:TIMESERIES_CHART(Request& context) yAxisLeftFormat: , yAxisRightFormat: }); - chart.setData(, ); + chart.setData(, ); window[] = chart; }()); @@ -151,17 +151,17 @@ COMPONENT:SORTABLE_TABLE(Request& context) starter_register_js("js/u-format.js", context); starter_register_js("js/u-sortable-table.js", context); - String table_id = first(context.call["id"].to_string(), "sortable-table-" + std::to_string((u64)time())); - String title = context.call["title"].to_string(); - String subtitle = context.call["subtitle"].to_string(); - String empty_label = first(context.call["empty_label"].to_string(), "No data available"); + String table_id = first(context.props["id"].to_string(), "sortable-table-" + std::to_string((u64)time())); + String title = context.props["title"].to_string(); + String subtitle = context.props["subtitle"].to_string(); + String empty_label = first(context.props["empty_label"].to_string(), "No data available"); DTree init_options; - init_options["storageKey"] = first(context.call["storage_key"].to_string(), "starter.sort." + table_id); - if(context.call["sort"]["column"].to_string() != "") + init_options["storageKey"] = first(context.props["storage_key"].to_string(), "starter.sort." + table_id); + if(context.props["sort"]["column"].to_string() != "") { - init_options["initialSort"]["column"] = context.call["sort"]["column"]; - init_options["initialSort"]["direction"] = first(context.call["sort"]["direction"].to_string(), "asc"); + init_options["initialSort"]["column"] = context.props["sort"]["column"]; + init_options["initialSort"]["direction"] = first(context.props["sort"]["direction"].to_string(), "asc"); } <> @@ -176,7 +176,7 @@ COMPONENT:SORTABLE_TABLE(Request& context) - - - + + - 0 && columns._map.find("0") != columns._map.end() && columns["0"]["field"].to_string() != ""; - if(!has_explicit_columns && context.call["items"]["0"].get_type_name() == "array") + if(!has_explicit_columns && context.props["items"]["0"].get_type_name() == "array") { - context.call["items"]["0"].each([&](DTree value, String key) { + context.props["items"]["0"].each([&](DTree value, String key) { DTree col; col["field"] = key; col["headerName"] = key; @@ -248,7 +248,7 @@ COMPONENT:DATA_TABLE(Request& context) columns = normalized_columns; } - DTree row_data = context.call["items"]; + DTree row_data = context.props["items"]; if(row_data.get_type_name() != "array") row_data.set_array(); if(!row_data.is_list()) @@ -264,7 +264,7 @@ COMPONENT:DATA_TABLE(Request& context) DTree grid_options; grid_options["pagination"].set_bool(true); - grid_options["paginationPageSize"] = first(context.call["options"]["paginationPageSize"].to_string(), "20"); + grid_options["paginationPageSize"] = first(context.props["options"]["paginationPageSize"].to_string(), "20"); grid_options["paginationPageSizeSelector"].set_bool(false); grid_options["suppressMenuHide"].set_bool(true); grid_options["animateRows"].set_bool(true); @@ -275,7 +275,7 @@ COMPONENT:DATA_TABLE(Request& context)
- rows + rows
@@ -283,7 +283,7 @@ COMPONENT:DATA_TABLE(Request& context)
-
; width: 100%; border: 1px solid var(--border); border-radius: 0 0 0.5rem 0.5rem; overflow: hidden;">
+
; width: 100%; border: 1px solid var(--border); border-radius: 0 0 0.5rem 0.5rem; overflow: hidden;">
diff --git a/site/examples/uce-starter/components/gauges/needlegauge.uce b/site/examples/uce-starter/components/gauges/needlegauge.uce index 25ed3f1..6cdf28b 100644 --- a/site/examples/uce-starter/components/gauges/needlegauge.uce +++ b/site/examples/uce-starter/components/gauges/needlegauge.uce @@ -5,15 +5,15 @@ COMPONENT(Request& context) starter_register_js("components/gauges/common.js", context); starter_register_css("themes/common/css/gauges.css", context); - String gauge_id = first(context.call["id"].to_string(), "needlegauge-" + std::to_string((u64)time())); - String style = context.call["style"].to_string(); - String title = context.call["title"].to_string(); - String subtitle = context.call["subtitle"].to_string(); - f64 size = float_val(first(context.call["size"].to_string(), "200")); - DTree scale = context.call["scale"]; + String gauge_id = first(context.props["id"].to_string(), "needlegauge-" + std::to_string((u64)time())); + String style = context.props["style"].to_string(); + 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"]; 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.call["img_height"].to_string(), std::to_string(size * std::max(cos(scale_angle_start), cos(scale_angle_end))))); + 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))))); <>
@@ -24,7 +24,7 @@ COMPONENT(Request& context)
-
- + diff --git a/site/examples/uce-starter/components/gauges/progressbar.uce b/site/examples/uce-starter/components/gauges/progressbar.uce index 1410243..33e95e8 100644 --- a/site/examples/uce-starter/components/gauges/progressbar.uce +++ b/site/examples/uce-starter/components/gauges/progressbar.uce @@ -5,18 +5,18 @@ COMPONENT(Request& context) starter_register_js("components/gauges/common.js", context); starter_register_css("themes/common/css/gauges.css", context); - String gauge_id = first(context.call["id"].to_string(), "progressbar-" + std::to_string((u64)time())); - String style = context.call["style"].to_string(); - String item_style = context.call["item-style"].to_string(); - String label_style = context.call["label-style"].to_string(); - String value_style = context.call["value-style"].to_string(); - String bar_style = context.call["bar-style"].to_string(); - String title = context.call["title"].to_string(); - String subtitle = context.call["subtitle"].to_string(); - String layout = first(context.call["layout"].to_string(), "horizontal"); - String bar_color_default = context.call["bar-color"].to_string(); - DTree scale = context.call["scale"]; - DTree markers = context.call["markers"]; + String gauge_id = first(context.props["id"].to_string(), "progressbar-" + std::to_string((u64)time())); + String style = context.props["style"].to_string(); + String item_style = context.props["item-style"].to_string(); + String label_style = context.props["label-style"].to_string(); + String value_style = context.props["value-style"].to_string(); + String bar_style = context.props["bar-style"].to_string(); + String title = context.props["title"].to_string(); + 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"]; StringList default_palette; default_palette.push_back("var(--success, #10b981)"); @@ -35,7 +35,7 @@ COMPONENT(Request& context)
-
-
px;"> - px;"> + - + diff --git a/site/examples/uce-starter/components/theme/account_links.uce b/site/examples/uce-starter/components/theme/account_links.uce index 96018c2..35203ea 100644 --- a/site/examples/uce-starter/components/theme/account_links.uce +++ b/site/examples/uce-starter/components/theme/account_links.uce @@ -7,9 +7,9 @@ COMPONENT(Request& context) DTree 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.call["wrapper_class"].to_string(), theme_key == "localfirst" ? "admin-account-card" : "nav-account nav-menu"); - String links_class = first(context.call["links_wrapper_class"].to_string(), theme_key == "localfirst" ? "admin-account-links" : ""); - String name_class = first(context.call["name_class"].to_string(), theme_key == "localfirst" ? "admin-account-name" : "account-name"); + String wrapper_class = first(context.props["wrapper_class"].to_string(), theme_key == "localfirst" ? "admin-account-card" : "nav-account nav-menu"); + String links_class = first(context.props["links_wrapper_class"].to_string(), theme_key == "localfirst" ? "admin-account-links" : ""); + String name_class = first(context.props["name_class"].to_string(), theme_key == "localfirst" ? "admin-account-name" : "account-name"); <>
diff --git a/site/examples/uce-starter/components/theme/footer.uce b/site/examples/uce-starter/components/theme/footer.uce index 1a81513..46b4e99 100644 --- a/site/examples/uce-starter/components/theme/footer.uce +++ b/site/examples/uce-starter/components/theme/footer.uce @@ -8,7 +8,7 @@ COMPONENT(Request& context) return; String text = first(context.cfg.get_by_path("theme/footer_text").to_string(), context.cfg.get_by_path("site/name").to_string()); - String inner_class = first(context.call["inner_class"].to_string(), context.cfg.get_by_path("theme/key").to_string() == "portal-light" ? "footer-inner" : ""); + String inner_class = first(context.props["inner_class"].to_string(), context.cfg.get_by_path("theme/key").to_string() == "portal-light" ? "footer-inner" : ""); <>
diff --git a/site/examples/uce-starter/components/theme/global_controls.uce b/site/examples/uce-starter/components/theme/global_controls.uce index 9af2162..81c320c 100644 --- a/site/examples/uce-starter/components/theme/global_controls.uce +++ b/site/examples/uce-starter/components/theme/global_controls.uce @@ -6,7 +6,7 @@ COMPONENT(Request& context) if(starter_page_embed_mode(context)) return; - String cookie_value = context.call["cookie_consent"].to_string(); + String cookie_value = context.props["cookie_consent"].to_string(); bool cookie_consent = !(cookie_value == "0" || cookie_value == "false" || cookie_value == "FALSE" || cookie_value == "no" || cookie_value == "NO"); <> diff --git a/site/examples/uce-starter/components/theme/page_shell.uce b/site/examples/uce-starter/components/theme/page_shell.uce index 890f2c2..43cc9e5 100644 --- a/site/examples/uce-starter/components/theme/page_shell.uce +++ b/site/examples/uce-starter/components/theme/page_shell.uce @@ -3,18 +3,18 @@ COMPONENT(Request& context) { starter_boot(context); - if(context.call["main_html"].to_string() != "") - context.var["starter"]["fragments"]["main"] = context.call["main_html"]; - if(context.call["json"].get_type_name() == "array") - context.var["starter"]["json"] = context.call["json"]; - if(context.call["page_type"].to_string() != "") - context.var["starter"]["page_type"] = context.call["page_type"]; - if(context.call["embed_mode"].to_string() != "") - context.var["starter"]["embed_mode"] = context.call["embed_mode"]; + if(context.props["main_html"].to_string() != "") + context.var["starter"]["fragments"]["main"] = context.props["main_html"]; + if(context.props["json"].get_type_name() == "array") + context.var["starter"]["json"] = context.props["json"]; + if(context.props["page_type"].to_string() != "") + context.var["starter"]["page_type"] = context.props["page_type"]; + if(context.props["embed_mode"].to_string() != "") + context.var["starter"]["embed_mode"] = context.props["embed_mode"]; starter_render_page(context); } COMPONENT:HEAD(Request& context) { - print(component("head", context.call, context)); + print(component("head", context.props, context)); } diff --git a/site/examples/uce-starter/components/theme/standard_nav.uce b/site/examples/uce-starter/components/theme/standard_nav.uce index 587548a..2ab90ec 100644 --- a/site/examples/uce-starter/components/theme/standard_nav.uce +++ b/site/examples/uce-starter/components/theme/standard_nav.uce @@ -3,17 +3,17 @@ COMPONENT(Request& context) { starter_boot(context); - String nav_class = context.call["nav_class"].to_string(); + String nav_class = context.props["nav_class"].to_string(); 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; - if(context.call["account_wrapper_class"].to_string() != "") - account_props["wrapper_class"] = context.call["account_wrapper_class"]; - if(context.call["links_wrapper_class"].to_string() != "") - account_props["links_wrapper_class"] = context.call["links_wrapper_class"]; - if(context.call["name_class"].to_string() != "") - account_props["name_class"] = context.call["name_class"]; + 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() != "") + account_props["links_wrapper_class"] = context.props["links_wrapper_class"]; + if(context.props["name_class"].to_string() != "") + account_props["name_class"] = context.props["name_class"]; <> > diff --git a/site/examples/uce-starter/components/workspace/primitives.uce b/site/examples/uce-starter/components/workspace/primitives.uce index f63a2c3..30fc397 100644 --- a/site/examples/uce-starter/components/workspace/primitives.uce +++ b/site/examples/uce-starter/components/workspace/primitives.uce @@ -4,14 +4,14 @@ COMPONENT:APP_FRAME(Request& context) { starter_register_css("themes/common/css/workspace.css", context); starter_register_js("js/u-workspace-shell.js", context); - String id = context.call["id"].to_string(); - String overlay_id = context.call["overlay_id"].to_string(); - String class_name = context.call["class"].to_string(); + String id = context.props["id"].to_string(); + String overlay_id = context.props["overlay_id"].to_string(); + String class_name = context.props["class"].to_string(); <> class="ws-app"> - + class="ws-sidebar-overlay">
-
+
} @@ -19,11 +19,11 @@ COMPONENT:APP_FRAME(Request& context) COMPONENT:EMPTY_STATE(Request& context) { <> -
"> -
">
-

-

- +
"> +
">
+

+

+
} @@ -31,18 +31,18 @@ COMPONENT:EMPTY_STATE(Request& context) COMPONENT:LIST_STATE(Request& context) { <> -
">">
+
">">
} COMPONENT:MOBILE_BAR(Request& context) { <> -
"> - class="ws-mobile-toggle" title="Toggle sidebar" type="button"> - "> +
"> + class="ws-mobile-toggle" title="Toggle sidebar" type="button"> + "> - +
} @@ -50,12 +50,12 @@ COMPONENT:MOBILE_BAR(Request& context) COMPONENT:PANEL_HEADER(Request& context) { <> -
"> +
">
-

-

+

+

-
+
} @@ -63,9 +63,9 @@ COMPONENT:PANEL_HEADER(Request& context) COMPONENT:PANEL(Request& context) { <> - class="ws-panel"> - - + class="ws-panel"> + + } @@ -73,9 +73,9 @@ COMPONENT:PANEL(Request& context) COMPONENT:SECTION_HEAD(Request& context) { <> -
"> -

-
+
"> +

+
} @@ -83,9 +83,9 @@ COMPONENT:SECTION_HEAD(Request& context) COMPONENT:SECTION(Request& context) { <> - class="ws-section"> - - + class="ws-section"> + + } @@ -93,9 +93,9 @@ COMPONENT:SECTION(Request& context) COMPONENT:SIDEBAR_SHELL(Request& context) { <> - class="ws-sidebar"> - - + class="ws-sidebar"> + + } @@ -103,11 +103,11 @@ COMPONENT:SIDEBAR_SHELL(Request& context) COMPONENT:SIDEBAR_TOOLBAR(Request& context) { <> -
"> - +
"> +
- name="" class="ws-search-input" placeholder="" autocomplete="off"> + name="" class="ws-search-input" placeholder="" autocomplete="off">
@@ -115,8 +115,8 @@ COMPONENT:SIDEBAR_TOOLBAR(Request& context) COMPONENT:STATUS_PILL(Request& context) { - String variant = to_lower(first(context.call["variant"].to_string(), "neutral")); + String variant = to_lower(first(context.props["variant"].to_string(), "neutral")); <> - "> + "> } diff --git a/site/examples/uce-starter/lib/app.uce b/site/examples/uce-starter/lib/app.uce index 0a2d92f..49247c6 100644 --- a/site/examples/uce-starter/lib/app.uce +++ b/site/examples/uce-starter/lib/app.uce @@ -206,7 +206,7 @@ String app_html_class(Request& context) String app_page_main_html(Request& context) { - String main_html = context.call["main_html"].to_string(); + String main_html = context.props["main_html"].to_string(); if(main_html == "") main_html = context.var["app"]["fragments"]["main"].to_string(); return(main_html); @@ -236,9 +236,9 @@ bool app_request_embed_mode(Request& context) bool app_page_embed_mode(Request& context) { - String embed_value = context.call["embed_mode"].to_string(); + String embed_value = context.props["embed_mode"].to_string(); if(embed_value != "") - return(app_bool_value(context.call["embed_mode"])); + return(app_bool_value(context.props["embed_mode"])); return(app_request_embed_mode(context)); } diff --git a/site/examples/uce-starter/themes/common/page.json.uce b/site/examples/uce-starter/themes/common/page.json.uce index 975a1a8..99b4cfd 100644 --- a/site/examples/uce-starter/themes/common/page.json.uce +++ b/site/examples/uce-starter/themes/common/page.json.uce @@ -5,8 +5,8 @@ COMPONENT(Request& context) starter_boot(context); context.header["Content-Type"] = "application/json"; context.header["Cache-Control"] = "no-cache, no-store, must-revalidate"; - if(context.call["json"].get_type_name() == "array") - print(json_encode(context.call["json"])); + if(context.props["json"].get_type_name() == "array") + print(json_encode(context.props["json"])); else if(context.var["starter"]["json"].get_type_name() == "array") print(json_encode(context.var["starter"]["json"])); else diff --git a/site/examples/uce-starter/views/page1.uce b/site/examples/uce-starter/views/page1.uce index 0ee58c3..d44d6e1 100644 --- a/site/examples/uce-starter/views/page1.uce +++ b/site/examples/uce-starter/views/page1.uce @@ -20,7 +20,7 @@ RENDER(Request& context)
COMPONENT:HERO_SECTION(Request& context)
 {
-    String title = first(context.call["title"].to_string(), "Welcome");
+    String title = first(context.props["title"].to_string(), "Welcome");
     <>
         <div class="hero-section">...</div>
     </>
diff --git a/site/info/components/code_example.uce b/site/info/components/code_example.uce
new file mode 100644
index 0000000..0533545
--- /dev/null
+++ b/site/info/components/code_example.uce
@@ -0,0 +1,611 @@
+bool code_is_space(char ch)
+{
+	return(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
+}
+
+bool code_is_digit(char ch)
+{
+	return(ch >= '0' && ch <= '9');
+}
+
+bool code_is_alpha(char ch)
+{
+	return((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'));
+}
+
+bool code_is_ident_start(char ch)
+{
+	return(code_is_alpha(ch) || ch == '_');
+}
+
+bool code_is_ident_char(char ch)
+{
+	return(code_is_ident_start(ch) || code_is_digit(ch));
+}
+
+bool markup_name_char(char ch)
+{
+	return(code_is_ident_char(ch) || ch == '-' || ch == ':' || ch == '@');
+}
+
+bool code_is_punct(char ch)
+{
+	return(ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == '(' || ch == ')' || ch == ',' || ch == ';');
+}
+
+bool code_is_operator(char ch)
+{
+	return(ch == '=' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' || ch == '!' || ch == '<' || ch == '>' || ch == '&' || ch == '|' || ch == '.' || ch == ':' || ch == '?' || ch == '^');
+}
+
+bool code_has_prefix(String src, u64 i, String prefix)
+{
+	if(i + prefix.length() > src.length())
+		return(false);
+	return(substr(src, i, prefix.length()) == prefix);
+}
+
+String code_wrap(String cls, String text)
+{
+	if(text == "")
+		return("");
+	return("" + html_escape(text) + "");
+}
+
+String uce_markup_open_token()
+{
+	return("<" ">");
+}
+
+String uce_markup_close_token()
+{
+	return("");
+}
+
+String uce_code_open_token()
+{
+	return("<" "?");
+}
+
+String uce_code_expr_token()
+{
+	return("<" "?=");
+}
+
+String uce_code_raw_token()
+{
+	return("<" "?:");
+}
+
+String uce_code_close_token()
+{
+	return("?" ">");
+}
+
+bool cpp_keyword(String word)
+{
+	String lower = to_lower(word);
+	return(
+		word == "RENDER" ||
+		word == "COMPONENT" ||
+		word == "WS" ||
+		lower == "if" ||
+		lower == "else" ||
+		lower == "for" ||
+		lower == "while" ||
+		lower == "return" ||
+		lower == "const" ||
+		lower == "auto" ||
+		lower == "void" ||
+		lower == "bool" ||
+		lower == "true" ||
+		lower == "false"
+	);
+}
+
+bool cpp_type(String word)
+{
+	return(
+		word == "String" ||
+		word == "DTree" ||
+		word == "Request" ||
+		word == "StringList" ||
+		word == "StringMap" ||
+		word == "u64" ||
+		word == "u32" ||
+		word == "s64" ||
+		word == "f64"
+	);
+}
+
+bool cpp_builtin_call(String word)
+{
+	return(
+		word == "component" ||
+		word == "component_render" ||
+		word == "component_exists" ||
+		word == "component_resolve" ||
+		word == "markdown_to_ast" ||
+		word == "markdown_to_html" ||
+		word == "json_decode" ||
+		word == "json_encode" ||
+		word == "time_format_utc" ||
+		word == "first" ||
+		word == "contains" ||
+		word == "ws_send" ||
+		word == "ws_send_to" ||
+		word == "ws_message" ||
+		word == "ws_connection_id"
+	);
+}
+
+bool cpp_context_field(String word)
+{
+	return(
+		word == "get" ||
+		word == "post" ||
+		word == "session" ||
+		word == "call" ||
+		word == "connection" ||
+		word == "params" ||
+		word == "cookies" ||
+		word == "header" ||
+		word == "cfg"
+	);
+}
+
+bool nginx_keyword(String word)
+{
+	return(
+		word == "location" ||
+		word == "include" ||
+		word == "fastcgi_param" ||
+		word == "fastcgi_pass" ||
+		word == "proxy_pass" ||
+		word == "proxy_set_header" ||
+		word == "proxy_http_version" ||
+		word == "error_page" ||
+		word == "if" ||
+		word == "return" ||
+		word == "root" ||
+		word == "index" ||
+		word == "server" ||
+		word == "listen" ||
+		word == "server_name" ||
+		word == "map"
+	);
+}
+
+String highlight_cpp_fragment(String code)
+{
+	String out;
+	for(u64 i = 0; i < code.length(); )
+	{
+		if(code_has_prefix(code, i, "//"))
+		{
+			u64 start = i;
+			while(i < code.length() && code[i] != '\n')
+				i += 1;
+			out += code_wrap("comment", substr(code, start, i - start));
+			continue;
+		}
+
+		if(code_has_prefix(code, i, "/*"))
+		{
+			u64 start = i;
+			i += 2;
+			while(i < code.length() && !code_has_prefix(code, i, "*/"))
+				i += 1;
+			if(code_has_prefix(code, i, "*/"))
+				i += 2;
+			out += code_wrap("comment", substr(code, start, i - start));
+			continue;
+		}
+
+		char ch = code[i];
+		if(ch == '"' || ch == '\'' || ch == '`')
+		{
+			char quote = ch;
+			u64 start = i;
+			i += 1;
+			while(i < code.length())
+			{
+				if(code[i] == '\\' && i + 1 < code.length())
+				{
+					i += 2;
+					continue;
+				}
+				if(code[i] == quote)
+				{
+					i += 1;
+					break;
+				}
+				i += 1;
+			}
+			out += code_wrap("string", substr(code, start, i - start));
+			continue;
+		}
+
+		if(code_is_space(ch))
+		{
+			out += substr(code, i, 1);
+			i += 1;
+			continue;
+		}
+
+		if(code_is_digit(ch))
+		{
+			u64 start = i;
+			i += 1;
+			while(i < code.length())
+			{
+				char next = code[i];
+				if(code_is_digit(next) || next == '.' || next == 'x' || next == 'X' || next == '_' || (next >= 'a' && next <= 'f') || (next >= 'A' && next <= 'F'))
+					i += 1;
+				else
+					break;
+			}
+			out += code_wrap("number", substr(code, start, i - start));
+			continue;
+		}
+
+		if(code_is_ident_start(ch))
+		{
+			u64 start = i;
+			i += 1;
+			while(i < code.length() && code_is_ident_char(code[i]))
+				i += 1;
+			String word = substr(code, start, i - start);
+			u64 j = i;
+			while(j < code.length() && (code[j] == ' ' || code[j] == '\t'))
+				j += 1;
+
+			if(cpp_keyword(word))
+				out += code_wrap("keyword", word);
+			else if(cpp_type(word))
+				out += code_wrap("type", word);
+			else if(cpp_context_field(word))
+				out += code_wrap("field", word);
+			else if(word == "context" || word == "props" || word == "payload" || word == "ws")
+				out += code_wrap("variable", word);
+			else if(cpp_builtin_call(word))
+				out += code_wrap("builtin", word);
+			else if(j < code.length() && code[j] == '(')
+				out += code_wrap("call", word);
+			else
+				out += code_wrap("ident", word);
+			continue;
+		}
+
+		if(code_is_punct(ch))
+		{
+			out += code_wrap("punct", substr(code, i, 1));
+			i += 1;
+			continue;
+		}
+
+		if(code_is_operator(ch))
+		{
+			out += code_wrap("operator", substr(code, i, 1));
+			i += 1;
+			continue;
+		}
+
+		out += html_escape(substr(code, i, 1));
+		i += 1;
+	}
+	return(out);
+}
+
+String highlight_markup_tag(String tag)
+{
+	String out;
+	u64 i = 0;
+	if(code_has_prefix(tag, i, " name_start)
+		out += code_wrap("markup-tag", substr(tag, name_start, i - name_start));
+
+	while(i < tag.length())
+	{
+		if(code_is_space(tag[i]))
+		{
+			out += substr(tag, i, 1);
+			i += 1;
+			continue;
+		}
+
+		if(code_has_prefix(tag, i, "/>"))
+		{
+			out += code_wrap("delimiter", "/>" );
+			i += 2;
+			break;
+		}
+
+		if(code_has_prefix(tag, i, ">"))
+		{
+			out += code_wrap("delimiter", ">" );
+			i += 1;
+			break;
+		}
+
+		u64 attr_start = i;
+		while(i < tag.length() && markup_name_char(tag[i]))
+			i += 1;
+		if(i > attr_start)
+			out += code_wrap("markup-attr", substr(tag, attr_start, i - attr_start));
+
+		while(i < tag.length() && code_is_space(tag[i]))
+		{
+			out += substr(tag, i, 1);
+			i += 1;
+		}
+
+		if(i < tag.length() && tag[i] == '=')
+		{
+			out += code_wrap("operator", "=");
+			i += 1;
+			while(i < tag.length() && code_is_space(tag[i]))
+			{
+				out += substr(tag, i, 1);
+				i += 1;
+			}
+			if(i < tag.length() && (tag[i] == '"' || tag[i] == '\''))
+			{
+				char quote = tag[i];
+				u64 value_start = i;
+				i += 1;
+				while(i < tag.length() && tag[i] != quote)
+					i += 1;
+				if(i < tag.length())
+					i += 1;
+				out += code_wrap("string", substr(tag, value_start, i - value_start));
+			}
+			else
+			{
+				u64 value_start = i;
+				while(i < tag.length() && !code_is_space(tag[i]) && tag[i] != '>')
+					i += 1;
+				out += code_wrap("string", substr(tag, value_start, i - value_start));
+			}
+		}
+	}
+
+	return(out);
+}
+
+String highlight_uce_code(String code)
+{
+	String out;
+	bool in_markup = false;
+	String markup_open = uce_markup_open_token();
+	String markup_close = uce_markup_close_token();
+	String code_open = uce_code_open_token();
+	String code_expr = uce_code_expr_token();
+	String code_raw = uce_code_raw_token();
+	String code_close = uce_code_close_token();
+	for(u64 i = 0; i < code.length(); )
+	{
+		if(!in_markup)
+		{
+			s64 next_markup = strpos(code, markup_open, i);
+			if(next_markup < 0)
+			{
+				out += highlight_cpp_fragment(substr(code, i));
+				break;
+			}
+			if((u64)next_markup > i)
+				out += highlight_cpp_fragment(substr(code, i, (u64)next_markup - i));
+			out += code_wrap("delimiter", markup_open);
+			i = (u64)next_markup + 2;
+			in_markup = true;
+			continue;
+		}
+
+		if(code_has_prefix(code, i, markup_close))
+		{
+			out += code_wrap("delimiter", markup_close);
+			i += 3;
+			in_markup = false;
+			continue;
+		}
+
+		if(code_has_prefix(code, i, code_expr) || code_has_prefix(code, i, code_raw) || code_has_prefix(code, i, code_open))
+		{
+			String opener = code_has_prefix(code, i, code_expr) ? code_expr : (code_has_prefix(code, i, code_raw) ? code_raw : code_open);
+			out += code_wrap("delimiter", opener);
+			i += opener.length();
+			u64 island_start = i;
+			while(i < code.length() && !code_has_prefix(code, i, code_close))
+				i += 1;
+			out += highlight_cpp_fragment(substr(code, island_start, i - island_start));
+			if(code_has_prefix(code, i, code_close))
+			{
+				out += code_wrap("delimiter", code_close);
+				i += 2;
+			}
+			continue;
+		}
+
+		if(code_has_prefix(code, i, "<"))
+		{
+			u64 tag_start = i;
+			char quote = 0;
+			i += 1;
+			while(i < code.length())
+			{
+				if(quote != 0)
+				{
+					if(code[i] == quote)
+						quote = 0;
+					i += 1;
+					continue;
+				}
+				if(code[i] == '"' || code[i] == '\'')
+				{
+					quote = code[i];
+					i += 1;
+					continue;
+				}
+				if(code[i] == '>')
+				{
+					i += 1;
+					break;
+				}
+				i += 1;
+			}
+			out += highlight_markup_tag(substr(code, tag_start, i - tag_start));
+			continue;
+		}
+
+		u64 text_start = i;
+		while(i < code.length() && code[i] != '<')
+			i += 1;
+		out += code_wrap("markup-text", substr(code, text_start, i - text_start));
+	}
+	return(out);
+}
+
+String highlight_nginx_code(String code)
+{
+	String out;
+	for(u64 i = 0; i < code.length(); )
+	{
+		if(code[i] == '#')
+		{
+			u64 start = i;
+			while(i < code.length() && code[i] != '\n')
+				i += 1;
+			out += code_wrap("comment", substr(code, start, i - start));
+			continue;
+		}
+
+		if(code[i] == '"' || code[i] == '\'')
+		{
+			char quote = code[i];
+			u64 start = i;
+			i += 1;
+			while(i < code.length() && code[i] != quote)
+				i += 1;
+			if(i < code.length())
+				i += 1;
+			out += code_wrap("string", substr(code, start, i - start));
+			continue;
+		}
+
+		if(code_is_space(code[i]))
+		{
+			out += substr(code, i, 1);
+			i += 1;
+			continue;
+		}
+
+		if(code[i] == '$' || code[i] == '@')
+		{
+			u64 start = i;
+			i += 1;
+			while(i < code.length() && markup_name_char(code[i]))
+				i += 1;
+			out += code_wrap("variable", substr(code, start, i - start));
+			continue;
+		}
+
+		if(code_is_digit(code[i]))
+		{
+			u64 start = i;
+			i += 1;
+			while(i < code.length() && (code_is_digit(code[i]) || code[i] == '.'))
+				i += 1;
+			out += code_wrap("number", substr(code, start, i - start));
+			continue;
+		}
+
+		if(markup_name_char(code[i]))
+		{
+			u64 start = i;
+			i += 1;
+			while(i < code.length() && markup_name_char(code[i]))
+				i += 1;
+			String word = substr(code, start, i - start);
+			if(nginx_keyword(word))
+				out += code_wrap("keyword", word);
+			else
+				out += code_wrap("ident", word);
+			continue;
+		}
+
+		if(code_is_punct(code[i]))
+		{
+			out += code_wrap("punct", substr(code, i, 1));
+			i += 1;
+			continue;
+		}
+
+		if(code_is_operator(code[i]))
+		{
+			out += code_wrap("operator", substr(code, i, 1));
+			i += 1;
+			continue;
+		}
+
+		out += html_escape(substr(code, i, 1));
+		i += 1;
+	}
+	return(out);
+}
+
+String highlight_code(String code)
+{
+	if(contains(code, "fastcgi_pass") || contains(code, "proxy_pass"))
+		return(highlight_nginx_code(code));
+	return(highlight_uce_code(code));
+}
+
+String highlight_code(String code, String language)
+{
+	if(language == "nginx")
+		return(highlight_nginx_code(code));
+	if(language == "uce")
+		return(highlight_uce_code(code));
+	return(highlight_code(code));
+}
+
+String code_language_label(String language)
+{
+	if(language == "nginx")
+		return("nginx");
+	return("uce");
+}
+
+COMPONENT(Request& props)
+{
+	String eyebrow = props.props["eyebrow"].to_string();
+	String title = props.props["title"].to_string();
+	String summary = props.props["summary"].to_string();
+	String code = props.props["code"].to_string();
+	String note = props.props["note"].to_string();
+	String language = first(props.props["language"].to_string(), "uce");
+
+	<>
+
+

+

+
+ +
+
+
+
+} \ No newline at end of file diff --git a/site/info/index.uce b/site/info/index.uce index a0549d0..375cda1 100644 --- a/site/info/index.uce +++ b/site/info/index.uce @@ -29,609 +29,16 @@ void render_link_card(String href, String title, String body, String meta) } -bool code_is_space(char ch) +void render_code_example(Request& context, String eyebrow, String title, String summary, String code, String note, String language = "uce") { - return(ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); -} - -bool code_is_digit(char ch) -{ - return(ch >= '0' && ch <= '9'); -} - -bool code_is_alpha(char ch) -{ - return((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')); -} - -bool code_is_ident_start(char ch) -{ - return(code_is_alpha(ch) || ch == '_'); -} - -bool code_is_ident_char(char ch) -{ - return(code_is_ident_start(ch) || code_is_digit(ch)); -} - -bool markup_name_char(char ch) -{ - return(code_is_ident_char(ch) || ch == '-' || ch == ':' || ch == '@'); -} - -bool code_is_punct(char ch) -{ - return(ch == '{' || ch == '}' || ch == '[' || ch == ']' || ch == '(' || ch == ')' || ch == ',' || ch == ';'); -} - -bool code_is_operator(char ch) -{ - return(ch == '=' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '%' || ch == '!' || ch == '<' || ch == '>' || ch == '&' || ch == '|' || ch == '.' || ch == ':' || ch == '?' || ch == '^'); -} - -bool code_has_prefix(String src, u64 i, String prefix) -{ - if(i + prefix.length() > src.length()) - return(false); - return(substr(src, i, prefix.length()) == prefix); -} - -String code_wrap(String cls, String text) -{ - if(text == "") - return(""); - return("" + html_escape(text) + ""); -} - -String uce_markup_open_token() -{ - return("<" ">"); -} - -String uce_markup_close_token() -{ - return(""); -} - -String uce_code_open_token() -{ - return("<" "?"); -} - -String uce_code_expr_token() -{ - return("<" "?="); -} - -String uce_code_raw_token() -{ - return("<" "?:"); -} - -String uce_code_close_token() -{ - return("?" ">"); -} - -bool cpp_keyword(String word) -{ - String lower = to_lower(word); - return( - word == "RENDER" || - word == "COMPONENT" || - word == "WS" || - lower == "if" || - lower == "else" || - lower == "for" || - lower == "while" || - lower == "return" || - lower == "const" || - lower == "auto" || - lower == "void" || - lower == "bool" || - lower == "true" || - lower == "false" - ); -} - -bool cpp_type(String word) -{ - return( - word == "String" || - word == "DTree" || - word == "Request" || - word == "StringList" || - word == "StringMap" || - word == "u64" || - word == "u32" || - word == "s64" || - word == "f64" - ); -} - -bool cpp_builtin_call(String word) -{ - return( - word == "component" || - word == "component_render" || - word == "component_exists" || - word == "component_resolve" || - word == "markdown_to_ast" || - word == "markdown_to_html" || - word == "json_decode" || - word == "json_encode" || - word == "time_format_utc" || - word == "first" || - word == "contains" || - word == "ws_send" || - word == "ws_send_to" || - word == "ws_message" || - word == "ws_connection_id" - ); -} - -bool cpp_context_field(String word) -{ - return( - word == "get" || - word == "post" || - word == "session" || - word == "call" || - word == "connection" || - word == "params" || - word == "cookies" || - word == "header" || - word == "cfg" - ); -} - -bool nginx_keyword(String word) -{ - return( - word == "location" || - word == "include" || - word == "fastcgi_param" || - word == "fastcgi_pass" || - word == "proxy_pass" || - word == "proxy_set_header" || - word == "proxy_http_version" || - word == "error_page" || - word == "if" || - word == "return" || - word == "root" || - word == "index" || - word == "server" || - word == "listen" || - word == "server_name" || - word == "map" - ); -} - -String highlight_cpp_fragment(String code) -{ - String out; - for(u64 i = 0; i < code.length(); ) - { - if(code_has_prefix(code, i, "//")) - { - u64 start = i; - while(i < code.length() && code[i] != '\n') - i += 1; - out += code_wrap("comment", substr(code, start, i - start)); - continue; - } - - if(code_has_prefix(code, i, "/*")) - { - u64 start = i; - i += 2; - while(i < code.length() && !code_has_prefix(code, i, "*/")) - i += 1; - if(code_has_prefix(code, i, "*/")) - i += 2; - out += code_wrap("comment", substr(code, start, i - start)); - continue; - } - - char ch = code[i]; - if(ch == '"' || ch == '\'' || ch == '`') - { - char quote = ch; - u64 start = i; - i += 1; - while(i < code.length()) - { - if(code[i] == '\\' && i + 1 < code.length()) - { - i += 2; - continue; - } - if(code[i] == quote) - { - i += 1; - break; - } - i += 1; - } - out += code_wrap("string", substr(code, start, i - start)); - continue; - } - - if(code_is_space(ch)) - { - out += substr(code, i, 1); - i += 1; - continue; - } - - if(code_is_digit(ch)) - { - u64 start = i; - i += 1; - while(i < code.length()) - { - char next = code[i]; - if(code_is_digit(next) || next == '.' || next == 'x' || next == 'X' || next == '_' || (next >= 'a' && next <= 'f') || (next >= 'A' && next <= 'F')) - i += 1; - else - break; - } - out += code_wrap("number", substr(code, start, i - start)); - continue; - } - - if(code_is_ident_start(ch)) - { - u64 start = i; - i += 1; - while(i < code.length() && code_is_ident_char(code[i])) - i += 1; - String word = substr(code, start, i - start); - u64 j = i; - while(j < code.length() && (code[j] == ' ' || code[j] == '\t')) - j += 1; - - if(cpp_keyword(word)) - out += code_wrap("keyword", word); - else if(cpp_type(word)) - out += code_wrap("type", word); - else if(cpp_context_field(word)) - out += code_wrap("field", word); - else if(word == "context" || word == "props" || word == "payload" || word == "ws") - out += code_wrap("variable", word); - else if(cpp_builtin_call(word)) - out += code_wrap("builtin", word); - else if(j < code.length() && code[j] == '(') - out += code_wrap("call", word); - else - out += code_wrap("ident", word); - continue; - } - - if(code_is_punct(ch)) - { - out += code_wrap("punct", substr(code, i, 1)); - i += 1; - continue; - } - - if(code_is_operator(ch)) - { - out += code_wrap("operator", substr(code, i, 1)); - i += 1; - continue; - } - - out += html_escape(substr(code, i, 1)); - i += 1; - } - return(out); -} - -String highlight_markup_tag(String tag) -{ - String out; - u64 i = 0; - if(code_has_prefix(tag, i, " name_start) - out += code_wrap("markup-tag", substr(tag, name_start, i - name_start)); - - while(i < tag.length()) - { - if(code_is_space(tag[i])) - { - out += substr(tag, i, 1); - i += 1; - continue; - } - - if(code_has_prefix(tag, i, "/>")) - { - out += code_wrap("delimiter", "/>" ); - i += 2; - break; - } - - if(code_has_prefix(tag, i, ">")) - { - out += code_wrap("delimiter", ">" ); - i += 1; - break; - } - - u64 attr_start = i; - while(i < tag.length() && markup_name_char(tag[i])) - i += 1; - if(i > attr_start) - out += code_wrap("markup-attr", substr(tag, attr_start, i - attr_start)); - - while(i < tag.length() && code_is_space(tag[i])) - { - out += substr(tag, i, 1); - i += 1; - } - - if(i < tag.length() && tag[i] == '=') - { - out += code_wrap("operator", "="); - i += 1; - while(i < tag.length() && code_is_space(tag[i])) - { - out += substr(tag, i, 1); - i += 1; - } - if(i < tag.length() && (tag[i] == '"' || tag[i] == '\'')) - { - char quote = tag[i]; - u64 value_start = i; - i += 1; - while(i < tag.length() && tag[i] != quote) - i += 1; - if(i < tag.length()) - i += 1; - out += code_wrap("string", substr(tag, value_start, i - value_start)); - } - else - { - u64 value_start = i; - while(i < tag.length() && !code_is_space(tag[i]) && tag[i] != '>') - i += 1; - out += code_wrap("string", substr(tag, value_start, i - value_start)); - } - } - } - - return(out); -} - -String highlight_uce_code(String code) -{ - String out; - bool in_markup = false; - String markup_open = uce_markup_open_token(); - String markup_close = uce_markup_close_token(); - String code_open = uce_code_open_token(); - String code_expr = uce_code_expr_token(); - String code_raw = uce_code_raw_token(); - String code_close = uce_code_close_token(); - for(u64 i = 0; i < code.length(); ) - { - if(!in_markup) - { - s64 next_markup = strpos(code, markup_open, i); - if(next_markup < 0) - { - out += highlight_cpp_fragment(substr(code, i)); - break; - } - if((u64)next_markup > i) - out += highlight_cpp_fragment(substr(code, i, (u64)next_markup - i)); - out += code_wrap("delimiter", markup_open); - i = (u64)next_markup + 2; - in_markup = true; - continue; - } - - if(code_has_prefix(code, i, markup_close)) - { - out += code_wrap("delimiter", markup_close); - i += 3; - in_markup = false; - continue; - } - - if(code_has_prefix(code, i, code_expr) || code_has_prefix(code, i, code_raw) || code_has_prefix(code, i, code_open)) - { - String opener = code_has_prefix(code, i, code_expr) ? code_expr : (code_has_prefix(code, i, code_raw) ? code_raw : code_open); - out += code_wrap("delimiter", opener); - i += opener.length(); - u64 island_start = i; - while(i < code.length() && !code_has_prefix(code, i, code_close)) - i += 1; - out += highlight_cpp_fragment(substr(code, island_start, i - island_start)); - if(code_has_prefix(code, i, code_close)) - { - out += code_wrap("delimiter", code_close); - i += 2; - } - continue; - } - - if(code_has_prefix(code, i, "<")) - { - u64 tag_start = i; - char quote = 0; - i += 1; - while(i < code.length()) - { - if(quote != 0) - { - if(code[i] == quote) - quote = 0; - i += 1; - continue; - } - if(code[i] == '"' || code[i] == '\'') - { - quote = code[i]; - i += 1; - continue; - } - if(code[i] == '>') - { - i += 1; - break; - } - i += 1; - } - out += highlight_markup_tag(substr(code, tag_start, i - tag_start)); - continue; - } - - u64 text_start = i; - while(i < code.length() && code[i] != '<') - i += 1; - out += code_wrap("markup-text", substr(code, text_start, i - text_start)); - } - return(out); -} - -String highlight_nginx_code(String code) -{ - String out; - for(u64 i = 0; i < code.length(); ) - { - if(code[i] == '#') - { - u64 start = i; - while(i < code.length() && code[i] != '\n') - i += 1; - out += code_wrap("comment", substr(code, start, i - start)); - continue; - } - - if(code[i] == '"' || code[i] == '\'') - { - char quote = code[i]; - u64 start = i; - i += 1; - while(i < code.length() && code[i] != quote) - i += 1; - if(i < code.length()) - i += 1; - out += code_wrap("string", substr(code, start, i - start)); - continue; - } - - if(code_is_space(code[i])) - { - out += substr(code, i, 1); - i += 1; - continue; - } - - if(code[i] == '$' || code[i] == '@') - { - u64 start = i; - i += 1; - while(i < code.length() && markup_name_char(code[i])) - i += 1; - out += code_wrap("variable", substr(code, start, i - start)); - continue; - } - - if(code_is_digit(code[i])) - { - u64 start = i; - i += 1; - while(i < code.length() && (code_is_digit(code[i]) || code[i] == '.')) - i += 1; - out += code_wrap("number", substr(code, start, i - start)); - continue; - } - - if(markup_name_char(code[i])) - { - u64 start = i; - i += 1; - while(i < code.length() && markup_name_char(code[i])) - i += 1; - String word = substr(code, start, i - start); - if(nginx_keyword(word)) - out += code_wrap("keyword", word); - else - out += code_wrap("ident", word); - continue; - } - - if(code_is_punct(code[i])) - { - out += code_wrap("punct", substr(code, i, 1)); - i += 1; - continue; - } - - if(code_is_operator(code[i])) - { - out += code_wrap("operator", substr(code, i, 1)); - i += 1; - continue; - } - - out += html_escape(substr(code, i, 1)); - i += 1; - } - return(out); -} - -String highlight_code(String code) -{ - if(contains(code, "fastcgi_pass") || contains(code, "proxy_pass")) - return(highlight_nginx_code(code)); - return(highlight_uce_code(code)); -} - -String highlight_code(String code, String language) -{ - if(language == "nginx") - return(highlight_nginx_code(code)); - if(language == "uce") - return(highlight_uce_code(code)); - return(highlight_code(code)); -} - -String code_language_label(String language) -{ - if(language == "nginx") - return("nginx"); - return("uce"); -} - -void render_code_example(String eyebrow, String title, String summary, String code, String note, String language = "uce") -{ - <>
-
-

-

-
- -
-
-
-
+ DTree props; + props["eyebrow"] = eyebrow; + props["title"] = title; + props["summary"] = summary; + props["code"] = code; + props["note"] = note; + props["language"] = language; + <> } RENDER(Request& context) @@ -670,8 +77,8 @@ RENDER(Request& context) "{\n" "\t<>\n" "\t\t
\n" - "\t\t\t

\n" - "\t\t\t

\n" + "\t\t\t

\n" + "\t\t\t

\n" "\t\t
\n" "\t\n" "}\n\n" @@ -708,8 +115,10 @@ RENDER(Request& context) "}\n\n" "WS(Request& context)\n" "{\n" - "\tDTree payload = json_decode(ws_message());\n" + "\tDTree payload = json_decode(context.in);\n" + "\tString connection_id = context.params[\"WS_CONNECTION_ID\"];\n" "\tcontext.connection[\"name\"] = payload[\"name\"];\n" + "\tpayload[\"connection_id\"] = connection_id;\n" "\tws_send(json_encode(payload));\n" "}\n"; @@ -802,7 +211,7 @@ RENDER(Request& context)
- +
@@ -839,12 +248,12 @@ RENDER(Request& context)

- - - - - - + + + + + +
diff --git a/site/info/style.css b/site/info/style.css index 486434d..da04ca3 100644 --- a/site/info/style.css +++ b/site/info/style.css @@ -1,3 +1,8 @@ +/* UCE /info/ — modernized editorial theme + * Keeps the navy + gold palette and b612 / Input Sans Condensed fonts. + * Flat surfaces, hairline rules, numbered sections, typography-forward. + */ + @font-face { font-family: 'default_sans'; src: url('themes/common/fonts/b612/b612-regular.ttf') format('truetype'); @@ -39,30 +44,31 @@ } :root { - --bg: #113399; - --bg-deep: #0c2370; - --bg-grad: linear-gradient(160deg, #1d44b5 0%, #113399 42%, #0b225f 100%); - --surface: rgba(255, 255, 255, 0.065); - --surface-strong: rgba(255, 255, 255, 0.1); - --surface-hover: rgba(255, 255, 255, 0.13); - --surface-inset: rgba(7, 17, 52, 0.8); - --border: rgba(255, 255, 255, 0.08); - --border-strong: rgba(255, 255, 255, 0.16); - --text: #e7edf8; - --text-dim: rgba(215, 226, 245, 0.72); - --text-muted: rgba(215, 226, 245, 0.48); - --accent: #f0c430; - --accent-soft: rgba(240, 196, 48, 0.12); - --accent-hover: #ffe07c; - --shadow-sm: 0 10px 28px rgba(0, 0, 0, 0.18); - --shadow-md: 0 22px 48px rgba(0, 0, 0, 0.24); - --shadow-lg: 0 30px 80px rgba(0, 0, 0, 0.34); - --radius: 16px; - --radius-lg: 26px; - --font-sans: 'default_sans', sans-serif; - --font-mono: 'default_mono', monospace; - --font-display: 'display_condensed', 'default_sans', sans-serif; - --ease: cubic-bezier(0.22, 1, 0.36, 1); + --navy: #0a1f52; + --navy-deep: #06143a; + --navy-mid: #113399; + --navy-surface: #0d2472; + --navy-surface2: #112b82; + --navy-edge: #1a3fa8; + --ink: #eef2fb; + --ink-dim: rgba(228, 236, 250, 0.72); + --ink-muted: rgba(228, 236, 250, 0.46); + --rule: rgba(255, 255, 255, 0.10); + --rule-soft: rgba(255, 255, 255, 0.05); + --rule-strong: rgba(255, 255, 255, 0.18); + --gold: #f0c430; + --gold-hot: #ffe07c; + --gold-soft: rgba(240, 196, 48, 0.14); + --gold-edge: rgba(240, 196, 48, 0.32); + --radius-xs: 3px; + --radius-sm: 6px; + --radius: 10px; + --font-sans: 'default_sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + --font-mono: 'default_mono', ui-monospace, 'SFMono-Regular', Menlo, Consolas, monospace; + --font-display: 'display_condensed', 'default_sans', sans-serif; + --ease: cubic-bezier(0.22, 1, 0.36, 1); + --content: 1120px; + --gutter: clamp(20px, 4vw, 48px); } *, *::before, *::after { @@ -82,18 +88,20 @@ html { scroll-behavior: smooth; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + overflow-x: hidden; } body { - margin: 0; min-height: 100vh; - background: - radial-gradient(circle at top left, rgba(255, 255, 255, 0.08), transparent 32%), - radial-gradient(circle at 85% 12%, rgba(240, 196, 48, 0.13), transparent 22%), - var(--bg-grad); - color: var(--text); + background: #113399; + background-image: + radial-gradient(1100px 520px at 82% -8%, rgba(240, 196, 48, 0.10), transparent 60%), + radial-gradient(900px 620px at -5% 12%, rgba(120, 170, 255, 0.10), transparent 58%), + linear-gradient(168deg, #1a3daa 0%, #113399 40%, #0d2880 100%); + background-attachment: fixed; + color: var(--ink); font-family: var(--font-sans); - font-size: 1rem; + font-size: 0.98rem; line-height: 1.65; } @@ -101,416 +109,569 @@ body::before { content: ''; position: fixed; inset: 0; - background-image: - linear-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px), - linear-gradient(90deg, rgba(255, 255, 255, 0.04) 1px, transparent 1px); - background-size: 24px 24px; - opacity: 0.18; pointer-events: none; - mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.4), transparent 88%); + background-image: + linear-gradient(rgba(255, 255, 255, 0.028) 1px, transparent 1px), + linear-gradient(90deg, rgba(255, 255, 255, 0.028) 1px, transparent 1px); + background-size: 56px 56px; + mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.5), transparent 80%); + -webkit-mask-image: linear-gradient(180deg, rgba(0, 0, 0, 0.5), transparent 80%); + z-index: 0; } a { - color: var(--accent); + color: var(--gold); text-decoration: none; - transition: color 160ms var(--ease), transform 160ms var(--ease), border-color 160ms var(--ease), background 160ms var(--ease); + transition: color 140ms var(--ease), border-color 140ms var(--ease), background 140ms var(--ease); } -a:hover { - color: var(--accent-hover); -} +a:hover { color: var(--gold-hot); } -code, -pre, +code, pre, .brand, .eyebrow, +.code-lang, +.topbar nav a, +.topbar-link, .link-meta, .signal-card strong, -.deploy-card li, -.topbar nav a { +summary { font-family: var(--font-mono); } .page-shell { - width: min(1180px, calc(100% - 32px)); + width: min(var(--content), calc(100% - 32px)); margin: 0 auto; - padding: 20px 0 56px; + padding: 0 0 96px; position: relative; z-index: 1; } +/* ---------- Topbar ---------- */ + .topbar { position: sticky; - top: 14px; + top: 0; z-index: 10; display: flex; align-items: center; - gap: 16px; - padding: 14px 18px; - margin-bottom: 24px; - background: rgba(8, 20, 66, 0.7); - backdrop-filter: blur(16px); - -webkit-backdrop-filter: blur(16px); - border: 1px solid var(--border); - border-radius: 999px; - box-shadow: var(--shadow-sm); + gap: 18px; + padding: 18px 0 14px; + margin-bottom: 72px; + background: transparent; + border-bottom: 1px solid var(--rule); +} + +.topbar::before { + content: ''; + position: absolute; + top: 0; + bottom: 0; + left: 50%; + width: 100vw; + transform: translateX(-50%); + background: linear-gradient(180deg, rgba(13, 40, 128, 0.92), rgba(13, 40, 128, 0.68)); + backdrop-filter: saturate(140%) blur(10px); + -webkit-backdrop-filter: saturate(140%) blur(10px); + border-bottom: 1px solid var(--rule); + z-index: -1; + pointer-events: none; } .brand { - font-size: 1.05rem; + display: inline-flex; + align-items: center; + gap: 10px; + font-family: var(--font-mono); + font-size: 0.86rem; font-weight: 700; - letter-spacing: 0.08em; + letter-spacing: 0.22em; text-transform: uppercase; - color: var(--text); - padding-right: 8px; + color: var(--ink); +} + +.brand::before { + content: ''; + width: 10px; + height: 10px; + background: var(--gold); + transform: rotate(45deg); } .topbar nav { display: flex; flex-wrap: wrap; - gap: 6px; + gap: 2px; + margin-left: 8px; } -.topbar nav a, -.topbar-link { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 8px 12px; - border-radius: 999px; - border: 1px solid transparent; - color: var(--text-dim); - font-size: 0.88rem; +.topbar nav a { + padding: 6px 10px; + color: var(--ink-dim); + font-size: 0.82rem; + letter-spacing: 0.04em; + border-bottom: 1px solid transparent; } -.topbar nav a:hover, -.topbar-link:hover { - border-color: var(--border-strong); - background: rgba(255, 255, 255, 0.06); - color: var(--text); - transform: translateY(-1px); +.topbar nav a:hover { + color: var(--ink); + border-bottom-color: var(--gold); } .topbar-link { margin-left: auto; - background: var(--accent-soft); - color: var(--accent); - border-color: rgba(240, 196, 48, 0.24); + display: inline-flex; + align-items: center; + gap: 8px; + padding: 7px 12px 7px 14px; + font-family: var(--font-mono); + font-size: 0.82rem; + font-weight: 700; + letter-spacing: 0.06em; + color: var(--gold); + background: var(--gold-soft); + border: 1px solid var(--gold-edge); + border-radius: var(--radius-sm); } -main { - display: grid; - gap: 22px; +.topbar-link::after { + content: '→'; + color: var(--gold); + transition: transform 160ms var(--ease); } -.hero-panel, -.section, -.page-footer { - position: relative; - overflow: hidden; - background: var(--surface); - backdrop-filter: blur(18px); - -webkit-backdrop-filter: blur(18px); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - box-shadow: var(--shadow-sm); - padding: 28px; +.topbar-link:hover { + color: var(--gold-hot); + background: rgba(240, 196, 48, 0.22); } -.hero-panel::after, -.section::after { - content: ''; - position: absolute; - inset: auto -10% -40% auto; - width: 280px; - height: 280px; - border-radius: 50%; - background: radial-gradient(circle, rgba(240, 196, 48, 0.12), transparent 70%); - pointer-events: none; +.topbar-link:hover::after { transform: translateX(3px); color: var(--gold-hot); } + +/* ---------- Typography ---------- */ + +h1, h2, h3 { + color: var(--ink); } -.hero-panel { - display: grid; - grid-template-columns: minmax(0, 1.4fr) minmax(280px, 0.8fr); - gap: 24px; - align-items: start; - padding: 34px; - box-shadow: var(--shadow-lg); +h1 { + font-family: var(--font-display); + font-size: clamp(2.6rem, 6.4vw, 5.4rem); + line-height: 0.98; + letter-spacing: -0.025em; + text-transform: uppercase; + margin-bottom: 26px; + max-width: 18ch; + text-wrap: balance; } -.hero-copy, -.hero-aside, -.section-heading, -.feature-grid, -.code-grid, -.link-grid, -.deploy-grid, -.manifesto-grid, -.signal-grid { - position: relative; - z-index: 1; +h2 { + font-family: var(--font-display); + font-size: clamp(1.75rem, 3vw, 2.5rem); + line-height: 1.02; + letter-spacing: -0.01em; + text-transform: uppercase; + margin-bottom: 14px; + max-width: 24ch; + text-wrap: balance; } +h3 { + font-family: var(--font-sans); + font-size: 1.04rem; + font-weight: 700; + letter-spacing: -0.005em; + line-height: 1.25; + margin-bottom: 10px; +} + +p, li, summary { + color: var(--ink-dim); +} + +p + p { margin-top: 12px; } + +ul { list-style: none; padding-left: 0; } + +li + li { margin-top: 8px; } + .eyebrow { display: inline-flex; align-items: center; gap: 8px; - padding: 6px 10px; - margin-bottom: 14px; + padding: 3px 9px 3px 9px; border-radius: 999px; - background: rgba(255, 255, 255, 0.08); - color: var(--accent); - font-size: 0.74rem; + background: var(--gold-soft); + color: var(--gold); + border: 1px solid var(--gold-edge); + font-family: var(--font-mono); + font-size: 0.68rem; font-weight: 700; - letter-spacing: 0.08em; - text-transform: uppercase; -} - -h1, -h2, -h3 { - line-height: 1.08; - letter-spacing: -0.03em; -} - -h1, -h2 { - font-family: var(--font-display); + letter-spacing: 0.16em; text-transform: uppercase; margin-bottom: 16px; } -h1 { - font-size: clamp(3rem, 8vw, 6rem); - max-width: 10ch; - text-wrap: balance; +.eyebrow::before { + content: ''; + width: 5px; + height: 5px; + background: var(--gold); + border-radius: 50%; } -h2 { - font-size: clamp(1.9rem, 3.2vw, 3rem); - max-width: 14ch; +/* ---------- Main flow + numbered sections ---------- */ + +main { + display: flex; + flex-direction: column; + gap: 88px; + counter-reset: section; } -h3 { +.section { + position: relative; + counter-increment: section; +} + +.section > .section-heading::before { + content: '§ ' counter(section, decimal-leading-zero); + display: block; font-family: var(--font-mono); - font-size: 1.08rem; - margin-bottom: 10px; + font-size: 0.74rem; + font-weight: 700; + letter-spacing: 0.26em; + color: var(--gold); + margin-bottom: 18px; + text-transform: uppercase; } -p, -li, -summary, -.code-note, -.manual-card span, -.signal-card span, -.link-card span { - color: var(--text-dim); -} - -p + p { - margin-top: 12px; -} - -ul { - padding-left: 18px; -} - -li + li { - margin-top: 8px; -} - -.hero-lead, +.section-heading { margin-bottom: 32px; max-width: 72ch; } +.section-heading .eyebrow { display: none; } .section-heading p { - max-width: 70ch; - font-size: 1.05rem; + color: var(--ink-dim); + font-size: 1.02rem; + max-width: 66ch; + margin-top: 10px; +} + +/* ---------- Hero ---------- */ + +.hero-panel { + display: grid; + grid-template-columns: minmax(0, 1.5fr) minmax(280px, 1fr); + gap: 60px; + align-items: start; + padding: 0; + margin-bottom: 16px; + counter-increment: none; +} + +.hero-copy .eyebrow { margin-bottom: 20px; } + +.hero-copy h1 { + background: linear-gradient(180deg, #f6f9ff 0%, #cfdcf6 100%); + -webkit-background-clip: text; + background-clip: text; + color: transparent; +} + +.hero-lead { + font-size: 1.1rem; + color: var(--ink-dim); + max-width: 56ch; + margin-bottom: 26px; } .hero-actions { display: flex; flex-wrap: wrap; - gap: 12px; - margin: 26px 0 28px; + gap: 10px; + margin: 6px 0 36px; } .button { display: inline-flex; align-items: center; - justify-content: center; - padding: 12px 18px; - border-radius: 999px; - border: 1px solid var(--border-strong); + gap: 8px; + padding: 11px 18px; + border-radius: var(--radius-sm); font-family: var(--font-mono); - font-size: 0.9rem; + font-size: 0.88rem; font-weight: 700; - letter-spacing: 0.03em; - text-decoration: none; - box-shadow: var(--shadow-sm); + letter-spacing: 0.02em; + border: 1px solid transparent; + transition: transform 160ms var(--ease), background 160ms var(--ease), color 160ms var(--ease), border-color 160ms var(--ease); } -.button:hover { - text-decoration: none; - transform: translateY(-2px); - box-shadow: var(--shadow-md); -} +.button:hover { transform: translateY(-1px); text-decoration: none; } .button-primary { - background: var(--accent); - color: #1a2247; - border-color: rgba(255, 224, 124, 0.42); -} - -.button-primary:hover { - color: #1a2247; - background: var(--accent-hover); + background: var(--gold); + color: #1a1a1a; + border-color: var(--gold); + box-shadow: 0 8px 22px rgba(240, 196, 48, 0.22); } +.button-primary:hover { background: var(--gold-hot); color: #111; border-color: var(--gold-hot); } +.button-primary::after { content: '→'; } .button-secondary { - background: rgba(255, 255, 255, 0.06); - color: var(--text); + background: transparent; + color: var(--ink); + border-color: var(--rule-strong); +} +.button-secondary:hover { background: rgba(255, 255, 255, 0.05); border-color: rgba(255, 255, 255, 0.28); } + +/* Hero aside — editorial sidebar with hairline */ +.hero-aside { + display: flex; + flex-direction: column; + gap: 28px; + padding: 4px 0 0 28px; + border-left: 1px solid var(--rule); + align-self: stretch; } -.signal-grid, -.feature-grid, -.manifesto-grid, -.link-grid, -.deploy-grid { - display: grid; - gap: 14px; +.manual-card { + padding: 0; + background: transparent; + border: 0; } +.manual-card .eyebrow { + margin-bottom: 10px; +} + +.manual-card h2 { + font-family: var(--font-sans); + text-transform: none; + font-size: 1.15rem; + letter-spacing: -0.01em; + line-height: 1.25; + margin-bottom: 14px; + max-width: none; +} + +.manual-card ul { + display: flex; + flex-direction: column; + gap: 10px; +} + +.manual-card li { + color: var(--ink-dim); + font-size: 0.93rem; + line-height: 1.5; + padding-left: 18px; + position: relative; +} + +.manual-card li::before { + content: ''; + position: absolute; + left: 0; + top: 0.68em; + width: 8px; + height: 1px; + background: var(--gold); +} + +.manual-card.compact { padding-top: 18px; border-top: 1px solid var(--rule); } +.manual-card.compact p { font-size: 0.9rem; } +.manual-card.compact p + p { margin-top: 6px; } + +/* Hero signals row */ .signal-grid { + display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); - margin-top: 8px; + gap: 0; + margin-top: 36px; + border-top: 1px solid var(--rule); + border-bottom: 1px solid var(--rule); } -.feature-grid, -.link-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); - margin-top: 22px; +.signal-card { + padding: 18px 22px 18px 0; + background: transparent; + border-right: 1px solid var(--rule); } +.signal-card:last-child { border-right: 0; } +.signal-card + .signal-card { padding-left: 22px; } + +.signal-card strong { + display: block; + color: var(--ink); + font-size: 0.74rem; + font-weight: 700; + letter-spacing: 0.14em; + text-transform: uppercase; + margin-bottom: 6px; +} + +.signal-card span { + color: var(--ink-dim); + font-size: 0.93rem; +} + +/* ---------- Feature grid (Why) ---------- */ + +.feature-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0; + border-top: 1px solid var(--rule); +} + +.feature-card { + padding: 26px 28px 26px 0; + background: transparent; + border: 0; + border-bottom: 1px solid var(--rule); + border-right: 1px solid var(--rule); + position: relative; +} + +.feature-card:nth-child(2n) { padding-right: 0; padding-left: 28px; border-right: 0; } +.feature-card:nth-last-child(-n+2):not(:nth-last-child(n+3)) { border-bottom: 0; } + +.feature-card .eyebrow { + background: transparent; + border: 0; + padding: 0; + color: var(--ink-muted); + font-size: 0.66rem; + letter-spacing: 0.2em; + margin-bottom: 10px; +} +.feature-card .eyebrow::before { display: none; } + +.feature-card h3 { + font-size: 1.08rem; + margin-bottom: 8px; +} + +.feature-card p { font-size: 0.95rem; } + +/* ---------- Manifesto ---------- */ + .manifesto-grid { - grid-template-columns: repeat(3, minmax(0, 1fr)); - margin-top: 10px; -} - -.deploy-grid { - grid-template-columns: repeat(2, minmax(0, 1fr)); - margin-top: 14px; -} - -.signal-card, -.feature-card, -.manual-card, -.manifesto-card, -.deploy-card, -.link-card, -.code-card { - background: rgba(6, 16, 54, 0.52); - border: 1px solid var(--border); - border-radius: var(--radius); - box-shadow: var(--shadow-sm); - transition: transform 180ms var(--ease), border-color 180ms var(--ease), background 180ms var(--ease), box-shadow 180ms var(--ease); -} - -.signal-card, -.feature-card, -.manual-card, -.manifesto-card, -.deploy-card { - padding: 18px; -} - -.signal-card strong, -.link-card strong { - font-size: 0.9rem; - color: var(--text); - display: block; - margin-bottom: 8px; -} - -.feature-card:hover, -.link-card:hover, -.code-card:hover, -.manual-card:hover, -.manifesto-card:hover, -.deploy-card:hover, -.signal-card:hover { - transform: translateY(-2px); - border-color: var(--border-strong); - background: rgba(10, 24, 75, 0.72); - box-shadow: var(--shadow-md); -} - -.hero-aside { display: grid; - gap: 14px; -} - -.manual-card.compact p + p { + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 20px; margin-top: 10px; } -.section-heading { - margin-bottom: 8px; +.manifesto-card { + position: relative; + padding: 28px 24px 26px; + background: rgba(255, 255, 255, 0.05); + border: 1px solid var(--rule); + border-radius: var(--radius); } +.manifesto-card::before { + position: absolute; + top: 16px; + right: 18px; + font-family: var(--font-mono); + font-size: 1.6rem; + font-weight: 700; + color: var(--ink-muted); + line-height: 1; +} +.manifesto-card:nth-child(1)::before { content: '+'; color: #7ce7d5; } +.manifesto-card:nth-child(2)::before { content: '−'; color: #ff8ea1; } +.manifesto-card:nth-child(3)::before { content: '='; color: var(--gold); } + +.manifesto-card h3 { + font-size: 1.06rem; + color: var(--ink); + margin-bottom: 10px; + padding-right: 28px; +} + +.manifesto-card p { font-size: 0.95rem; } + .manifesto-card.emphasis { - background: linear-gradient(180deg, rgba(240, 196, 48, 0.14), rgba(255, 255, 255, 0.06)); - border-color: rgba(240, 196, 48, 0.2); + background: linear-gradient(180deg, rgba(240, 196, 48, 0.14), rgba(240, 196, 48, 0.04)); + border-color: var(--gold-edge); } +/* ---------- Examples: code cards ---------- */ + .code-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 16px; - margin-top: 20px; + gap: 20px; } .code-card { - padding: 20px; + display: flex; + flex-direction: column; + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--rule); + border-radius: var(--radius); overflow: hidden; + transition: border-color 160ms var(--ease), transform 160ms var(--ease); } -.code-card p { - min-height: 4.6em; - margin-bottom: 14px; +.code-card:hover { + border-color: var(--gold-edge); + transform: translateY(-1px); +} + +.code-card .eyebrow { margin: 22px 22px 12px; } +.code-card h3 { padding: 0 22px; margin-bottom: 6px; } +.code-card > p { + padding: 0 22px 16px; + font-size: 0.94rem; + color: var(--ink-dim); } .code-toolbar { display: flex; - justify-content: flex-end; - margin-bottom: 8px; + align-items: center; + justify-content: space-between; + padding: 8px 14px; + background: rgba(5, 18, 60, 0.85); + border-top: 1px solid var(--rule); + border-bottom: 1px solid var(--rule); +} + +.code-toolbar::before { + content: ''; + display: inline-flex; + width: 46px; + height: 10px; + background: + radial-gradient(circle at 5px 5px, #ff6b6b 4px, transparent 4.3px), + radial-gradient(circle at 21px 5px, #f0c430 4px, transparent 4.3px), + radial-gradient(circle at 37px 5px, #7ce7d5 4px, transparent 4.3px); + opacity: 0.82; } .code-lang { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 4px 8px; - border-radius: 999px; - background: rgba(255, 255, 255, 0.08); - border: 1px solid rgba(255, 255, 255, 0.12); - font-family: var(--font-mono); - font-size: 0.68rem; + font-size: 0.7rem; font-weight: 700; - letter-spacing: 0.08em; + letter-spacing: 0.16em; text-transform: uppercase; - color: var(--accent); + color: var(--ink-muted); + padding: 3px 9px; + border: 1px solid var(--rule); + border-radius: 999px; + background: rgba(255, 255, 255, 0.03); } .syntax-block { + margin: 0; + padding: 18px 20px; + background: rgba(0, 0, 0, 0.32); + border: 0; + border-radius: 0; overflow-x: auto; - padding: 18px; - border-radius: 14px; - border: 1px solid rgba(255, 255, 255, 0.08); - background: - linear-gradient(180deg, rgba(3, 9, 31, 0.97), rgba(8, 16, 48, 0.98)), - radial-gradient(circle at top right, rgba(240, 196, 48, 0.08), transparent 34%); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); - font-size: 0.88rem; - line-height: 1.6; - color: #f3f6fc; + font-size: 0.84rem; + line-height: 1.55; + color: #eef2fb; } .syntax-code { @@ -518,226 +679,252 @@ li + li { white-space: pre; min-width: max-content; font-family: var(--font-mono); - color: #f3f6fc; + color: inherit; tab-size: 2; -moz-tab-size: 2; font-variant-ligatures: none; } -.tok-comment { - color: #7f8db7; - font-style: italic; -} - -.tok-keyword, -.tok-delimiter { - color: #ff8ea1; - font-weight: 700; -} - -.tok-type { - color: #8bd9ff; -} - -.tok-builtin { - color: #7ce7d5; - font-weight: 700; -} - -.tok-call { - color: #f7d774; -} - -.tok-variable { - color: #b8a7ff; -} - -.tok-field { - color: #b6c9ff; -} - -.tok-string { - color: #8ce6b4; -} - -.tok-number { - color: #ffbf7a; -} - -.tok-operator, -.tok-punct { - color: #d8e1ff; -} - -.tok-ident { - color: #dfe7fb; -} - -.tok-markup-tag { - color: #7ee3ff; - font-weight: 700; -} - -.tok-markup-attr { - color: #ffd27c; -} - -.tok-markup-text { - color: #c9d5f4; -} - .code-note { - margin-top: 12px; - font-size: 0.92rem; + padding: 12px 20px; + margin: 0; + font-size: 0.86rem; + color: var(--ink-muted); + border-top: 1px solid var(--rule); + background: rgba(255, 255, 255, 0.02); +} + +/* Syntax tokens — tuned for the deep-navy code panel */ +.tok-comment { color: #7a8bb8; font-style: italic; } +.tok-keyword, +.tok-delimiter { color: #ff8ea1; font-weight: 700; } +.tok-type { color: #8bd9ff; } +.tok-builtin { color: #7ce7d5; font-weight: 700; } +.tok-call { color: #f7d774; } +.tok-variable { color: #b8a7ff; } +.tok-field { color: #b6c9ff; } +.tok-string { color: #8ce6b4; } +.tok-number { color: #ffbf7a; } +.tok-operator, +.tok-punct { color: #d8e1ff; } +.tok-ident { color: #dfe7fb; } +.tok-markup-tag { color: #7ee3ff; font-weight: 700; } +.tok-markup-attr { color: #ffd27c; } +.tok-markup-text { color: #c9d5f4; } + +/* ---------- Deploy ---------- */ + +.deploy-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0; + border-top: 1px solid var(--rule); + border-bottom: 1px solid var(--rule); +} + +.deploy-card { + padding: 28px 28px 28px 0; + background: transparent; + border: 0; + border-right: 1px solid var(--rule); +} +.deploy-card:last-child { padding-right: 0; padding-left: 28px; border-right: 0; } + +.deploy-card h3 { + font-size: 1.06rem; + margin-bottom: 14px; +} + +.deploy-card li { + color: var(--ink-dim); + font-size: 0.94rem; + padding-left: 22px; + position: relative; + line-height: 1.5; +} + +.deploy-card li::before { + content: '›'; + position: absolute; + left: 2px; + top: -1px; + color: var(--gold); + font-weight: 700; +} + +.deploy-card code, +.deploy-card li { word-break: break-word; } + +/* ---------- Link cards (Explore) ---------- */ + +.link-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 14px; } .link-card { display: block; - padding: 20px; - text-decoration: none; + padding: 20px 22px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--rule); + border-radius: var(--radius); + color: var(--ink); + position: relative; + transition: border-color 160ms var(--ease), background 160ms var(--ease), transform 160ms var(--ease); +} + +.link-card::after { + content: '→'; + position: absolute; + top: 18px; + right: 20px; + color: var(--ink-muted); + font-family: var(--font-mono); + transition: transform 160ms var(--ease), color 160ms var(--ease); } .link-card:hover { - text-decoration: none; + border-color: var(--gold-edge); + background: rgba(255, 255, 255, 0.08); + transform: translateY(-1px); } -.link-meta { - font-size: 0.76rem; - letter-spacing: 0.08em; +.link-card:hover::after { color: var(--gold); transform: translateX(3px); } + +.link-card .link-meta { + display: block; + font-size: 0.68rem; + letter-spacing: 0.18em; text-transform: uppercase; - color: var(--accent); + color: var(--ink-muted); margin-bottom: 10px; } -.deployment ul, -.manual-card ul, -.deploy-card ul { - list-style: none; - padding-left: 0; +.link-card:hover .link-meta { color: var(--gold); } + +.link-card strong { + display: block; + color: var(--ink); + font-size: 1rem; + margin-bottom: 6px; } -.deployment li, -.manual-card li, -.deploy-card li { - position: relative; - padding-left: 18px; +.link-card span { + color: var(--ink-dim); + font-size: 0.9rem; + line-height: 1.5; } -.deployment li::before, -.manual-card li::before, -.deploy-card li::before { - content: '+'; - position: absolute; - left: 0; - color: var(--accent); -} +/* ---------- FAQ ---------- */ -details { - padding: 18px 20px; - border: 1px solid var(--border); +.faq details { + padding: 18px 22px; + background: rgba(255, 255, 255, 0.04); + border: 1px solid var(--rule); border-radius: var(--radius); - background: rgba(6, 16, 54, 0.48); } -details + details { - margin-top: 12px; -} +.faq details + details { margin-top: 10px; } -summary { +.faq summary { cursor: pointer; list-style: none; font-family: var(--font-mono); - font-size: 0.96rem; - color: var(--text); + font-size: 0.94rem; + color: var(--ink); + position: relative; + padding-right: 28px; } -summary::-webkit-details-marker { - display: none; +.faq summary::-webkit-details-marker { display: none; } + +.faq summary::after { + content: '+'; + position: absolute; + right: 0; + top: -1px; + color: var(--gold); + font-size: 1.1rem; + font-weight: 700; + line-height: 1; + transition: transform 160ms var(--ease); } -details p { - margin-top: 12px; -} +.faq details[open] summary::after { transform: rotate(45deg); } + +.faq details p { margin-top: 12px; color: var(--ink-dim); font-size: 0.96rem; } + +/* ---------- Footer ---------- */ .page-footer { + margin-top: 24px; + padding: 26px 0 0; + border-top: 1px solid var(--rule); display: flex; + flex-wrap: wrap; justify-content: space-between; - gap: 18px; align-items: center; - margin-top: 4px; - padding-top: 20px; - padding-bottom: 20px; - background: rgba(7, 18, 56, 0.64); - border-radius: 20px; + gap: 16px; } .page-footer p { - max-width: 55ch; - font-size: 0.94rem; + max-width: 60ch; + font-size: 0.92rem; + color: var(--ink-muted); } +.page-footer p:last-child { + font-family: var(--font-mono); + display: inline-flex; + gap: 4px; + align-items: center; +} + +.page-footer a { + color: var(--ink); + border-bottom: 1px solid transparent; +} +.page-footer a:hover { color: var(--gold); border-bottom-color: var(--gold); } + .page-footer span { - opacity: 0.42; - padding: 0 8px; + color: var(--ink-muted); + padding: 0 6px; } +/* ---------- Responsive ---------- */ + @media (max-width: 1024px) { - .hero-panel, - .signal-grid, - .feature-grid, - .manifesto-grid, - .code-grid, - .link-grid, - .deploy-grid, - .page-footer { - grid-template-columns: 1fr; - } - - .hero-panel { - padding: 28px; - } - - .page-footer { - display: grid; - } + .hero-panel { grid-template-columns: 1fr; gap: 40px; } + .hero-aside { border-left: 0; padding-left: 0; padding-top: 24px; border-top: 1px solid var(--rule); } + .manifesto-grid { grid-template-columns: 1fr; } + .code-grid { grid-template-columns: 1fr; } + .link-grid { grid-template-columns: repeat(2, 1fr); } + .deploy-grid { grid-template-columns: 1fr; border-bottom: 0; } + .deploy-card { border-right: 0; border-bottom: 1px solid var(--rule); padding: 22px 0; } + .deploy-card:last-child { padding-left: 0; border-bottom: 0; } + .feature-grid { grid-template-columns: 1fr; } + .feature-card { padding: 22px 0 !important; border-right: 0 !important; } } -@media (max-width: 760px) { - .page-shell { - width: min(100% - 20px, 1180px); - padding-top: 10px; - } +@media (max-width: 720px) { + .topbar { flex-wrap: wrap; gap: 10px; padding-top: 14px; } + .topbar-link { margin-left: 0; } + .signal-grid { grid-template-columns: 1fr; } + .signal-card { border-right: 0; border-bottom: 1px solid var(--rule); padding: 16px 0 !important; } + .signal-card:last-child { border-bottom: 0; } + .link-grid { grid-template-columns: 1fr; } + .button { width: 100%; justify-content: center; } + main { gap: 64px; } + .section > .section-heading::before { margin-bottom: 12px; } +} - .topbar { - border-radius: 24px; - padding: 14px; - flex-wrap: wrap; - } +/* ---------- Utility ---------- */ - .topbar-link { - margin-left: 0; - } +::selection { background: var(--gold); color: #111; } - .hero-panel, - .section, - .page-footer { - padding: 22px; - } - - h1 { - font-size: 2.8rem; - } - - h2 { - font-size: 2rem; - } - - .button { - width: 100%; - } - - pre { - padding: 16px; - font-size: 0.82rem; - } -} \ No newline at end of file +:focus-visible { + outline: 2px solid var(--gold); + outline-offset: 2px; + border-radius: var(--radius-xs); +} diff --git a/site/info/themes/common/page.json.uce b/site/info/themes/common/page.json.uce index 975a1a8..fcca43e 100644 --- a/site/info/themes/common/page.json.uce +++ b/site/info/themes/common/page.json.uce @@ -5,10 +5,8 @@ COMPONENT(Request& context) starter_boot(context); context.header["Content-Type"] = "application/json"; context.header["Cache-Control"] = "no-cache, no-store, must-revalidate"; - if(context.call["json"].get_type_name() == "array") - print(json_encode(context.call["json"])); - else if(context.var["starter"]["json"].get_type_name() == "array") - print(json_encode(context.var["starter"]["json"])); + if(context.props["json"].get_type_name() == "array") + print(json_encode(context.props["json"])); else print(starter_page_main_html(context)); } diff --git a/site/info/themes/dark/css/style.css b/site/info/themes/dark/css/style.css deleted file mode 100755 index 0b45533..0000000 --- a/site/info/themes/dark/css/style.css +++ /dev/null @@ -1,516 +0,0 @@ -:root { - /* Dark theme color palette */ - --bg-color: #0f172a; - --bg-secondary: #1e293b; - --bg-gradient: linear-gradient(135deg, #1e3a8a 0%, #3730a3 100%); - --surface: #1e293b; - --surface-elevated: #334155; - --surface-hover: #475569; - --primary: #60a5fa; - --primary-dark: #3b82f6; - --primary-light: #93c5fd; - --secondary: #a78bfa; - --accent: #22d3ee; - --text-primary: #f1f5f9; - --text-secondary: #cbd5e1; - --text-muted: #94a3b8; - --border: #334155; - --border-hover: #475569; - --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3); - --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3); - --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3); - --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.4); - --radius: 8px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-xl: 16px; - --radius-sm: 4px; - - /* Dark theme specific variables */ - --glass-bg: rgba(30, 41, 59, 0.8); - --glass-border: rgba(148, 163, 184, 0.1); - --overlay: rgba(0, 0, 0, 0.6); - --success: #10b981; - --success-bg: rgba(16, 185, 129, 0.1); - --success-border: rgba(16, 185, 129, 0.3); - --success-text: #10b981; - --warning: #f59e0b; - --warning-bg: rgba(245, 158, 11, 0.1); - --warning-border: rgba(245, 158, 11, 0.3); - --warning-text: #f59e0b; - --error: #ef4444; - --error-bg: rgba(239, 68, 68, 0.1); - --error-border: rgba(239, 68, 68, 0.3); - --error-text: #ef4444; - --info: #3b82f6; - --info-bg: rgba(59, 130, 246, 0.1); - --info-border: rgba(59, 130, 246, 0.3); - --info-text: #3b82f6; -} - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -html { - font-size: 16px; - scroll-behavior: smooth; -} - -body { - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - font-size: 1rem; - font-weight: 400; - line-height: 1.6; - color: var(--text-primary); - background: var(--bg-color); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -/* Links */ -a { - color: var(--primary); - text-decoration: none; - transition: all 0.2s ease; -} - -a:hover { - color: var(--primary-light); - text-decoration: underline; -} - -/* Modern Navigation */ -nav { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 1000; - background: var(--glass-bg); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - border-bottom: 1px solid var(--border); - padding: 0 1rem; - display: flex; - align-items: center; - box-shadow: var(--shadow-sm); - transition: all 0.3s ease; -} - -nav > a, -.nav-menu a { - display: inline-flex; - align-items: center; - padding: 0.625rem 1rem; - color: var(--text-primary); - text-decoration: none; - font-weight: 500; - transition: all 0.2s ease; - position: relative; - border-radius: var(--radius); - margin: 0.35rem 0.15rem; -} - -nav > a:first-child, -.nav-menu > a:first-child { - font-weight: 700; - color: var(--primary); - padding-left: 1.25rem; - padding-right: 1.25rem; -} - -nav > a:hover, -.nav-menu a:hover { - background: var(--surface-hover); - color: var(--primary); - text-decoration: none; -} - -nav > a::after, -.nav-menu a::after { - content: ''; - position: absolute; - bottom: 0; - left: 50%; - width: 0; - height: 2px; - background: var(--primary); - transition: all 0.3s ease; - transform: translateX(-50%); -} - -nav > a:hover::after, -.nav-menu a:hover::after { - width: 60%; -} - -/* Account area inside the nav */ -.nav-menu { - display: flex; - align-items: center; - gap: 0.25rem; -} - -.nav-account { - margin-left: auto; - display: flex; - align-items: center; - gap: 0.5rem; -} - -nav.nav-scrolled { - background: rgba(30, 41, 59, 0.95) !important; - backdrop-filter: blur(20px) !important; - -webkit-backdrop-filter: blur(20px) !important; - box-shadow: var(--shadow-md) !important; -} - -#content { - margin-top: 5rem; - min-height: calc(100vh - 10rem); - padding: 2rem 1rem; - max-width: 1200px; - margin-left: auto; - margin-right: auto; -} - -/* Typography */ -h1, h2, h3, h4, h5, h6 { - font-weight: 700; - line-height: 1.2; - margin-bottom: 1rem; - color: var(--text-primary); -} - -h1 { - font-size: 2rem; - position: relative; - padding-bottom: 0.75rem; - margin-bottom: 1.25rem; -} - -h1::before { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 60px; - height: 3px; - background: var(--bg-gradient); - border-radius: 3px; -} - -h2 { - font-size: 2rem; -} - -h3 { - font-size: 1.5rem; -} - -/* Modern Cards/Blocks */ -#content > div:not(.ws-app), .block, .card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - padding: 1.75rem; - margin-bottom: 1.5rem; - box-shadow: var(--shadow-sm); - transition: border-color 0.25s ease, box-shadow 0.25s ease; -} - -#content > div:not(.ws-app):hover, .block:hover, .card:hover { - box-shadow: var(--shadow-md); - border-color: var(--border-hover); -} - -/* Modern Forms */ -form { - max-width: 600px; - margin: 0 auto; -} - -form > div { - display: flex; - flex-direction: column; - margin-bottom: 1.5rem; - gap: 0.5rem; -} - -form > div > label { - font-weight: 500; - color: var(--text-secondary); - font-size: 0.875rem; - text-transform: uppercase; - letter-spacing: 0.05em; - transition: all 0.2s ease; -} - -form > div > input, form > div > textarea, form > div > select { - padding: 0.75rem 1rem; - border: 2px solid var(--border); - border-radius: var(--radius); - background: var(--bg-secondary); - color: var(--text-primary); - font-size: 1rem; - transition: all 0.2s ease; -} - -form > div > input:focus, form > div > textarea:focus, form > div > select:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.2); - background: var(--surface); -} - -/* Enhanced form validation states */ -form > div > input.valid, form > div > textarea.valid { - border-color: var(--success); - box-shadow: 0 0 0 3px var(--success-bg); -} - -form > div > input.invalid, form > div > textarea.invalid { - border-color: var(--error); - box-shadow: 0 0 0 3px var(--error-bg); -} - -/* Floating label effect */ -form > div.focused > label { - transform: translateY(-0.5rem) scale(0.85); - color: var(--primary); -} - -/* Modern Buttons */ -button, .btn, form > div > input[type=submit], input[type="submit"] { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0.75rem 1.5rem; - background: var(--primary); - color: var(--bg-color); - border: none; - border-radius: var(--radius); - font-weight: 500; - font-size: 1rem; - cursor: pointer; - transition: all 0.2s ease; - text-decoration: none; - position: relative; - overflow: hidden; -} - -button:hover, .btn:hover, form > div > input[type=submit]:hover, input[type="submit"]:hover { - background: var(--primary-dark); - transform: translateY(-1px); - box-shadow: var(--shadow-lg); -} - -button:active, .btn:active { - transform: translateY(0); -} - -input[type="range"] { - width: 100%; - height: 6px; - background: var(--bg-color); - outline: none; - border-radius: 3px; - -webkit-appearance: none; - appearance: none; -} - -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - appearance: none; - width: 20px; - height: 20px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - box-shadow: var(--shadow-sm); -} - -input[type="range"]::-moz-range-thumb { - width: 20px; - height: 20px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - border: none; - box-shadow: var(--shadow-sm); -} - -/* Button variants */ -.btn-secondary { - background: var(--secondary); -} - -.btn-secondary:hover { - background: #8b5cf6; -} - -.btn-outline { - background: transparent; - color: var(--primary); - border: 2px solid var(--primary); -} - -.btn-outline:hover { - background: var(--primary); - color: var(--bg-color); -} - -.btn-large { - padding: 1rem 2rem; - font-size: 1.125rem; -} - -/* Utility Classes */ -.banner { - padding: 1rem 1.5rem; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - margin-bottom: 1rem; -} - -.banner.success { - background: var(--success-bg); - border-color: var(--success-border); - color: var(--success); -} - -.banner.warning { - background: var(--warning-bg); - border-color: var(--warning-border); - color: var(--warning); -} - -.banner.error { - background: var(--error-bg); - border-color: var(--error-border); - color: var(--error); -} - -.error { - color: var(--error); -} - -/* Footer */ -footer { - text-align: center; - color: var(--text-muted); - padding: 2rem 1rem; - margin-top: 4rem; - border-top: 1px solid var(--border); - background: var(--surface); -} - -/* Mobile Responsive Design */ -@media (max-width: 768px) { - nav { - padding: 0 0.5rem; - overflow-x: auto; - white-space: nowrap; - scrollbar-width: none; - -ms-overflow-style: none; - } - - nav::-webkit-scrollbar { - display: none; - } - - nav > a { - padding: 0.75rem 1rem; - margin: 0.25rem 0.125rem; - font-size: 0.875rem; - display: inline-flex; - flex-shrink: 0; - } - - #content { - margin-top: 4rem; - padding: 1rem 0.5rem; - } - - h1 { - font-size: 1.875rem; - padding: 1.5rem; - } - - #content > div, .block, .card { - padding: 1.5rem; - margin-bottom: 1rem; - } - - form > div { - margin-bottom: 1rem; - } - - button, .btn { - padding: 0.875rem 1.25rem; - font-size: 0.9rem; - } -} - -@media (max-width: 480px) { - nav > a { - padding: 0.5rem 0.75rem; - font-size: 0.8rem; - } - - #content { - padding: 1rem 0.25rem; - } - - h1 { - font-size: 1.5rem; - padding: 1rem; - } - - #content > div, .block, .card { - padding: 1rem; - border-radius: var(--radius); - } -} - -/* Smooth scrolling and improved animations */ -* { - scroll-behavior: smooth; -} - -/* Loading animation for better perceived performance */ -@keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.5; } -} - -.loading { - animation: pulse 2s ease-in-out infinite; -} - -/* Focus states for accessibility */ -button:focus, .btn:focus, input:focus, textarea:focus, select:focus { - outline: 2px solid var(--primary); - outline-offset: 2px; -} - -/* Print styles */ -@media print { - nav, footer, .cta-section { - display: none; - } - - #content { - margin-top: 0; - } - - * { - background: white !important; - color: black !important; - box-shadow: none !important; - } -} diff --git a/site/info/themes/dark/icon.png b/site/info/themes/dark/icon.png deleted file mode 100755 index 8a42581..0000000 Binary files a/site/info/themes/dark/icon.png and /dev/null differ diff --git a/site/info/themes/dark/page.html.uce b/site/info/themes/dark/page.html.uce deleted file mode 100644 index 8645bb0..0000000 --- a/site/info/themes/dark/page.html.uce +++ /dev/null @@ -1,31 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - - DTree nav_props; - nav_props["account_wrapper_class"] = "nav-account nav-menu"; - - DTree footer_props; - footer_props["embed_mode"].set_bool(embed_mode); - - <> - - "> - - - - > - - -
> - -
- - - - -} diff --git a/site/info/themes/light/css/style.css b/site/info/themes/light/css/style.css deleted file mode 100755 index b872b44..0000000 --- a/site/info/themes/light/css/style.css +++ /dev/null @@ -1,540 +0,0 @@ -:root { - /* Light theme color palette */ - --bg-color: #f8fafc; - --bg-secondary: #ffffff; - --bg-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - --surface: #ffffff; - --surface-elevated: #ffffff; - --surface-hover: #f1f5f9; - --primary: #3b82f6; - --primary-dark: #1d4ed8; - --primary-light: #93c5fd; - --secondary: #8b5cf6; - --accent: #06b6d4; - --text-primary: #1e293b; - --text-secondary: #64748b; - --text-muted: #94a3b8; - --border: #e2e8f0; - --border-hover: #cbd5e1; - --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); - --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); - --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); - --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); - --radius: 8px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-xl: 16px; - --radius-sm: 4px; - - /* Light theme specific variables */ - --glass-bg: rgba(255, 255, 255, 0.95); - --glass-border: rgba(0, 0, 0, 0.1); - --overlay: rgba(0, 0, 0, 0.3); - --success: #10b981; - --success-bg: #dcfce7; - --success-border: #16a34a; - --success-text: #065f46; - --warning: #f59e0b; - --warning-bg: #fef3c7; - --warning-border: #d97706; - --warning-text: #92400e; - --error: #ef4444; - --error-bg: #fee2e2; - --error-border: #dc2626; - --error-text: #991b1b; - --info: #3b82f6; - --info-bg: #dbeafe; - --info-border: #2563eb; - --info-text: #1e40af; -} - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -html { - font-size: 16px; - scroll-behavior: smooth; -} - -body { - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - font-size: 1rem; - font-weight: 400; - line-height: 1.6; - color: var(--text-primary); - background: var(--bg-color); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -/* Links */ -a { - color: var(--primary); - text-decoration: none; - transition: all 0.2s ease; -} - -a:hover { - color: var(--primary-dark); - text-decoration: underline; -} - -/* Modern Navigation */ -nav { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 1000; - background: var(--glass-bg); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - border-bottom: 1px solid var(--border); - padding: 0 1rem; - display: flex; - align-items: center; - box-shadow: var(--shadow-sm); - transition: all 0.3s ease; -} - -nav > a, -.nav-menu a { - display: inline-flex; - align-items: center; - padding: 0.625rem 1rem; - color: var(--text-primary); - text-decoration: none; - font-weight: 500; - transition: all 0.2s ease; - position: relative; - border-radius: var(--radius); - margin: 0.35rem 0.15rem; -} - -nav > a:first-child, -.nav-menu > a:first-child { - font-weight: 700; - color: var(--primary); - padding-left: 1.25rem; - padding-right: 1.25rem; -} - -nav > a:hover, -.nav-menu a:hover { - background: var(--surface-hover); - color: var(--primary); - text-decoration: none; -} - -nav > a::after, -.nav-menu a::after { - content: ''; - position: absolute; - bottom: 0; - left: 50%; - width: 0; - height: 2px; - background: var(--primary); - transition: all 0.3s ease; - transform: translateX(-50%); -} - -nav > a:hover::after, -.nav-menu a:hover::after { - width: 60%; -} - -/* Account area inside the nav */ -.nav-menu { - display: flex; - align-items: center; - gap: 0.25rem; -} - -.nav-account { - margin-left: auto; - display: flex; - align-items: center; - gap: 0.5rem; -} - -.nav-account .account-name { - color: var(--text-secondary); - font-weight: 500; - margin-right: 0.5rem; - font-size: 0.95rem; -} - -.nav-account a { - display: inline-flex; - align-items: center; - padding: 0.5rem 0.75rem; - border-radius: var(--radius); - color: var(--text-primary); - text-decoration: none; -} - -.nav-account a:hover { - background: var(--surface-hover); - color: var(--primary-dark); -} - -/* Navigation scroll state */ -nav.nav-scrolled { - background: rgba(255, 255, 255, 0.98) !important; - backdrop-filter: blur(20px) !important; - -webkit-backdrop-filter: blur(20px) !important; - box-shadow: var(--shadow-md) !important; -} - -/* Main Content Area */ -#content { - margin-top: 5rem; - min-height: calc(100vh - 10rem); - padding: 2rem 1rem; - max-width: 1200px; - margin-left: auto; - margin-right: auto; -} - -/* Typography */ -h1, h2, h3, h4, h5, h6 { - font-weight: 700; - line-height: 1.2; - margin-bottom: 1rem; - color: var(--text-primary); -} - -h1 { - font-size: 2.5rem; - background: var(--surface); - padding: 1.75rem 2rem; - border-radius: var(--radius-lg); - box-shadow: var(--shadow-sm); - border: 1px solid var(--border); - position: relative; - overflow: hidden; -} - -h1::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 3px; - background: var(--bg-gradient); -} - -h2 { - font-size: 2rem; -} - -h3 { - font-size: 1.5rem; -} - -/* Modern Cards/Blocks */ -#content > div:not(.ws-app), .block, .card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - padding: 1.75rem; - margin-bottom: 1.5rem; - box-shadow: var(--shadow-sm); - transition: border-color 0.25s ease, box-shadow 0.25s ease; -} - -#content > div:not(.ws-app):hover, .block:hover, .card:hover { - box-shadow: var(--shadow-md); - border-color: var(--border-hover); -} - -/* Modern Forms */ -form { - max-width: 600px; - margin: 0 auto; -} - -form > div { - display: flex; - flex-direction: column; - margin-bottom: 1.5rem; - gap: 0.5rem; -} - -form > div > label { - font-weight: 500; - color: var(--text-secondary); - font-size: 0.875rem; - text-transform: uppercase; - letter-spacing: 0.05em; - transition: all 0.2s ease; -} - -form > div > input, form > div > textarea, form > div > select { - padding: 0.75rem 1rem; - border: 2px solid var(--border); - border-radius: var(--radius); - background: var(--surface); - color: var(--text-primary); - font-size: 1rem; - transition: all 0.2s ease; -} - -form > div > input:focus, form > div > textarea:focus, form > div > select:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); -} - -/* Enhanced form validation states */ -form > div > input.valid, form > div > textarea.valid { - border-color: var(--success); - box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1); -} - -form > div > input.invalid, form > div > textarea.invalid { - border-color: var(--error); - box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1); -} - -/* Floating label effect */ -form > div.focused > label { - transform: translateY(-0.5rem) scale(0.85); - color: var(--primary); -} - -/* Modern Buttons */ -button, .btn, form > div > input[type=submit], input[type="submit"] { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0.75rem 1.5rem; - background: var(--primary); - color: white; - border: none; - border-radius: var(--radius); - font-weight: 500; - font-size: 1rem; - cursor: pointer; - transition: all 0.2s ease; - text-decoration: none; - position: relative; - overflow: hidden; -} - -button:hover, .btn:hover, form > div > input[type=submit]:hover, input[type="submit"]:hover { - background: var(--primary-dark); - transform: translateY(-1px); - box-shadow: var(--shadow-lg); -} - -button:active, .btn:active { - transform: translateY(0); -} - -/* Button variants */ -.btn-secondary { - background: var(--secondary); -} - -.btn-secondary:hover { - background: #7c3aed; -} - -.btn-outline { - background: transparent; - color: var(--primary); - border: 2px solid var(--primary); -} - -.btn-outline:hover { - background: var(--primary); - color: white; -} - -.btn-large { - padding: 1rem 2rem; - font-size: 1.125rem; -} - -input[type="range"] { - width: 100%; - height: 6px; - background: var(--bg-color); - outline: none; - border-radius: 3px; - -webkit-appearance: none; - appearance: none; -} - -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - appearance: none; - width: 20px; - height: 20px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - box-shadow: var(--shadow-sm); -} - -input[type="range"]::-moz-range-thumb { - width: 20px; - height: 20px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - border: none; - box-shadow: var(--shadow-sm); -} - -/* Utility Classes */ -.banner { - padding: 1rem 1.5rem; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - margin-bottom: 1rem; -} - -.banner.success { - background: var(--success-bg); - border-color: var(--success-border); - color: var(--success); -} - -.banner.warning { - background: var(--warning-bg); - border-color: var(--warning-border); - color: var(--warning); -} - -.banner.error { - background: var(--error-bg); - border-color: var(--error-border); - color: var(--error); -} - -.error { - color: var(--error); -} - -/* Footer */ -footer { - text-align: center; - color: var(--text-muted); - padding: 2rem 1rem; - margin-top: 4rem; - border-top: 1px solid var(--border); - background: var(--surface); -} - -/* Mobile Responsive Design */ -@media (max-width: 768px) { - nav { - padding: 0 0.5rem; - overflow-x: auto; - white-space: nowrap; - scrollbar-width: none; - -ms-overflow-style: none; - } - - nav::-webkit-scrollbar { - display: none; - } - - nav > a { - padding: 0.75rem 1rem; - margin: 0.25rem 0.125rem; - font-size: 0.875rem; - display: inline-flex; - flex-shrink: 0; - } - - #content { - margin-top: 4rem; - padding: 1rem 0.5rem; - } - - h1 { - font-size: 1.875rem; - padding: 1.5rem; - } - - #content > div, .block, .card { - padding: 1.5rem; - margin-bottom: 1rem; - } - - form > div { - margin-bottom: 1rem; - } - - button, .btn { - padding: 0.875rem 1.25rem; - font-size: 0.9rem; - } -} - -@media (max-width: 480px) { - nav > a { - padding: 0.5rem 0.75rem; - font-size: 0.8rem; - } - - #content { - padding: 1rem 0.25rem; - } - - h1 { - font-size: 1.5rem; - padding: 1rem; - } - - #content > div, .block, .card { - padding: 1rem; - border-radius: var(--radius); - } -} - -/* Smooth scrolling and improved animations */ -* { - scroll-behavior: smooth; -} - -/* Loading animation for better perceived performance */ -@keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.5; } -} - -.loading { - animation: pulse 2s ease-in-out infinite; -} - -/* Focus states for accessibility */ -button:focus, .btn:focus, input:focus, textarea:focus, select:focus { - outline: 2px solid var(--primary); - outline-offset: 2px; -} - -/* Print styles */ -@media print { - nav, footer, .cta-section { - display: none; - } - - #content { - margin-top: 0; - } - - * { - background: white !important; - color: black !important; - box-shadow: none !important; - } -} diff --git a/site/info/themes/light/icon.png b/site/info/themes/light/icon.png deleted file mode 100755 index 8a42581..0000000 Binary files a/site/info/themes/light/icon.png and /dev/null differ diff --git a/site/info/themes/light/img/favicon.png b/site/info/themes/light/img/favicon.png deleted file mode 100755 index 6653d41..0000000 Binary files a/site/info/themes/light/img/favicon.png and /dev/null differ diff --git a/site/info/themes/light/page.html.uce b/site/info/themes/light/page.html.uce deleted file mode 100644 index 495d3e0..0000000 --- a/site/info/themes/light/page.html.uce +++ /dev/null @@ -1,28 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - - DTree footer_props; - footer_props["embed_mode"].set_bool(embed_mode); - - <> - - "> - - - - > - - -
> - -
- - - - -} diff --git a/site/info/themes/localfirst/css/style.css b/site/info/themes/localfirst/css/style.css deleted file mode 100644 index 088ce45..0000000 --- a/site/info/themes/localfirst/css/style.css +++ /dev/null @@ -1,382 +0,0 @@ -@font-face { - font-family: 'B612'; - src: url('../../common/fonts/b612/b612-regular.ttf') format('truetype'); - font-style: normal; - font-weight: 400; - font-display: swap; -} -@font-face { - font-family: 'B612'; - src: url('../../common/fonts/b612/b612-bold.ttf') format('truetype'); - font-style: normal; - font-weight: 700; - font-display: swap; -} -@font-face { - font-family: 'B612 Mono'; - src: url('../../common/fonts/b612/b612-mono-regular.ttf') format('truetype'); - font-style: normal; - font-weight: 400; - font-display: swap; -} -@font-face { - font-family: 'B612 Mono'; - src: url('../../common/fonts/b612/b612-mono-bold.ttf') format('truetype'); - font-style: normal; - font-weight: 700; - font-display: swap; -} - -@keyframes pulse-glow { - 0%, 100% { opacity: 1; box-shadow: 0 0 8px var(--accent), 0 0 16px rgba(255,107,26,0.28); } - 50% { opacity: 0.6; box-shadow: 0 0 4px var(--accent), 0 0 8px rgba(255,107,26,0.16); } -} - -:root { - --brand-cyan: #00b7f9; - --brand-cyan-soft: #58d2ff; - --brand-cyan-bright: #b6eeff; - --brand-cyan-deep: #0088bb; - --brand-orange: #ff6b1a; - --brand-orange-soft: #ff9f6a; - --brand-orange-bright: #ffd0b3; - --bg-color: #020913; - --bg-secondary: #07131f; - --surface: rgba(7, 19, 31, 0.9); - --surface-elevated: rgba(10, 28, 43, 0.96); - --surface-hover: rgba(0, 183, 249, 0.08); - --card: rgba(7, 19, 31, 0.84); - --text-primary: var(--brand-cyan-soft); - --text-secondary: rgba(139, 222, 255, 0.82); - --text-muted: rgba(101, 161, 188, 0.78); - --primary: var(--brand-cyan); - --primary-light: rgba(0, 183, 249, 0.18); - --primary-dark: var(--brand-cyan-deep); - --secondary: var(--brand-cyan-soft); - --accent: var(--brand-orange); - --success: #34d399; - --success-bg: rgba(52, 211, 153, 0.1); - --success-border: rgba(52, 211, 153, 0.3); - --success-text: #7ef0bb; - --warning: var(--brand-orange); - --warning-bg: rgba(255, 107, 26, 0.12); - --warning-border: rgba(255, 107, 26, 0.32); - --warning-text: #ffc29f; - --error: #fb7185; - --error-bg: rgba(251, 113, 133, 0.12); - --error-border: rgba(251, 113, 133, 0.3); - --error-text: #fecdd3; - --info: var(--brand-cyan); - --info-bg: rgba(0, 183, 249, 0.1); - --info-border: rgba(0, 183, 249, 0.28); - --info-text: var(--brand-cyan-bright); - --border: rgba(67, 149, 182, 0.22); - --border-hover: rgba(98, 205, 246, 0.36); - --shadow-sm: 0 8px 20px rgba(0, 0, 0, 0.18); - --shadow-md: 0 14px 32px rgba(0, 0, 0, 0.24); - --shadow-lg: 0 18px 38px rgba(0, 0, 0, 0.28); - --shadow-xl: 0 22px 48px rgba(0, 0, 0, 0.34); - --radius: 10px; - --radius-sm: 6px; - --radius-md: 10px; - --radius-lg: 16px; - --radius-xl: 20px; - --font-sans: 'B612', 'Segoe UI', sans-serif; - --font-mono: 'B612 Mono', ui-monospace, monospace; -} - -* { box-sizing: border-box; margin: 0; } -html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } -body { - font-family: var(--font-sans); - font-size: 14px; - background: var(--bg-color); - color: var(--text-primary); - min-height: 100vh; -} -body::before { - content: ''; - position: fixed; - inset: 0; - background: - radial-gradient(ellipse 80% 60% at 10% 0%, rgba(0,183,249,0.12) 0%, transparent 60%), - radial-gradient(ellipse 60% 50% at 90% 100%, rgba(255,107,26,0.08) 0%, transparent 60%); - pointer-events: none; - z-index: 0; -} -a { color: var(--accent); text-decoration: none; } -a:hover { text-decoration: underline; } - -body.admin-page { overflow: hidden; height: 100vh; } -.admin-shell { display: flex; height: 100vh; overflow: hidden; position: relative; z-index: 1; } -.admin-nav { - width: 210px; - flex-shrink: 0; - background: - linear-gradient(180deg, rgba(5, 16, 26, 0.98), rgba(2, 10, 18, 0.98)), - linear-gradient(180deg, rgba(0, 174, 240, 0.06), rgba(255, 107, 26, 0.04)); - border-right: 1px solid var(--border); - display: flex; - flex-direction: column; - overflow-y: auto; - padding: 0 0 16px; -} -.admin-nav-header { - border-bottom: 1px solid var(--border); - margin-bottom: 10px; - display: flex; - align-items: center; - gap: 9px; - padding: 10px 10px 12px; -} -.admin-nav-title { display: block; width: 100%; } -.admin-nav-logo-img { display: block; width: 100%; height: auto; } -.admin-nav-item { - display: block; - padding: 9px 16px 9px 14px; - text-decoration: none; - color: var(--text-secondary); - font-size: 12px; - text-transform: uppercase; - letter-spacing: 1px; - font-weight: 600; - transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease; - border-left: 3px solid transparent; -} -.admin-nav-item:hover { - color: var(--brand-cyan-bright); - background: linear-gradient(90deg, rgba(0, 174, 240, 0.12), rgba(255, 107, 26, 0.03)); - text-decoration: none; -} -.admin-nav-item.active { - color: var(--accent); - border-left-color: var(--accent); - background: linear-gradient(90deg, rgba(255, 107, 26, 0.16), rgba(255, 107, 26, 0.04)); - box-shadow: inset 0 0 0 1px rgba(255, 107, 26, 0.08); -} - -.admin-main { - flex: 1; - min-width: 0; - position: relative; - display: flex; - flex-direction: column; -} - -.admin-toolbar { - position: fixed; - top: 16px; - right: 20px; - z-index: 40; - display: flex; - justify-content: flex-end; - pointer-events: none; -} - -.admin-account-card { - pointer-events: auto; - display: inline-flex; - align-items: center; - gap: 10px; - padding: 8px 12px; - border-radius: 999px; - border: 1px solid var(--border); - background: rgba(7, 19, 31, 0.78); - box-shadow: var(--shadow-sm); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); -} -.admin-account-name { - color: var(--brand-cyan-bright); - font-size: 12px; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.08em; -} -.admin-account-links { - display: inline-flex; - gap: 10px; - align-items: center; -} -.admin-account-links a { - color: var(--accent); - font-size: 12px; - text-transform: uppercase; - letter-spacing: 0.08em; - font-weight: 700; -} - -.admin-content { - flex: 1; - overflow-y: auto; - padding: 16px 20px 28px; - position: relative; - min-width: 0; -} - -h1 { - font-size: 18px; - font-weight: 600; - letter-spacing: 1.4px; - text-transform: uppercase; - color: var(--brand-cyan-bright); - display: flex; - align-items: center; - gap: 10px; - margin: 0 0 14px; -} -h1::before { - content: ''; - display: inline-block; - width: 8px; - height: 8px; - background: var(--accent); - border-radius: 2px; - box-shadow: 0 0 8px var(--accent), 0 0 16px rgba(255,107,26,0.24); - animation: pulse-glow 2.5s ease-in-out infinite; -} -h2, h3, h4, h5, h6 { - color: var(--brand-cyan-bright); - margin: 0 0 10px; - text-transform: uppercase; - letter-spacing: 0.08em; -} -p { margin: 0 0 12px; color: var(--text-secondary); } - -.card, -.block, -.dashboard-panel, -#content > div:not(.ws-app):not(.demo-section) { - background: var(--card); - backdrop-filter: blur(16px); - -webkit-backdrop-filter: blur(16px); - border: 1px solid var(--border); - border-radius: var(--radius); - padding: 14px; - position: relative; - transition: border-color 0.25s ease, box-shadow 0.25s ease; - margin-bottom: 14px; -} -.card::before, -.block::before, -.dashboard-panel::before, -#content > div:not(.ws-app):not(.demo-section)::before { - content: ''; - position: absolute; - top: 0; - left: 12px; - right: 12px; - height: 1px; - background: linear-gradient(90deg, transparent, var(--primary), var(--accent), transparent); - opacity: 0.55; -} -.card:hover, -.block:hover, -.dashboard-panel:hover, -#content > div:not(.ws-app):not(.demo-section):hover { - border-color: var(--border-hover); - box-shadow: var(--shadow-md); -} - -form { max-width: 760px; } -form > div { display: grid; gap: 6px; margin-bottom: 12px; } -label { - color: var(--text-muted); - font-size: 12px; - text-transform: uppercase; - letter-spacing: 0.08em; - font-weight: 700; -} -input, select, textarea { - width: 100%; - border: 1px solid var(--border); - border-radius: var(--radius); - background: rgba(3, 7, 18, 0.55); - color: var(--brand-cyan-bright); - padding: 10px 12px; - font: inherit; -} -textarea { min-height: 120px; } -input:focus, select:focus, textarea:focus { - outline: none; - border-color: var(--border-hover); - box-shadow: 0 0 0 3px rgba(0, 183, 249, 0.12); -} -button, .btn, input[type="submit"] { - border: 1px solid var(--border); - background: rgba(255, 107, 26, 0.12); - color: var(--brand-orange-bright); - border-radius: var(--radius); - padding: 10px 14px; - font: inherit; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.08em; - cursor: pointer; - transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease; -} -button:hover, .btn:hover, input[type="submit"]:hover { - background: rgba(255, 107, 26, 0.18); - border-color: rgba(255, 107, 26, 0.42); - text-decoration: none; -} -button:active, .btn:active { transform: translateY(1px); } - -.banner { - border-radius: var(--radius); - padding: 10px 12px; - border: 1px solid var(--border); - background: rgba(0, 183, 249, 0.08); - color: var(--text-secondary); - margin-bottom: 12px; -} -.banner.success { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); } -.banner.warning { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning-text); } -.banner.error, .error { background: var(--error-bg); border-color: var(--error-border); color: var(--error-text); } - -table { - width: 100%; - border-collapse: collapse; - background: rgba(3, 7, 18, 0.42); - border: 1px solid var(--border); - border-radius: var(--radius); - overflow: hidden; -} -th, td { - padding: 10px 12px; - border-bottom: 1px solid var(--border); - text-align: left; - vertical-align: top; -} -th { - font-size: 12px; - letter-spacing: 0.08em; - text-transform: uppercase; - color: var(--text-muted); - background: rgba(0, 183, 249, 0.08); -} -tr:last-child td { border-bottom: none; } - -code, pre { font-family: var(--font-mono); } -pre { - padding: 12px; - background: rgba(3, 7, 18, 0.55); - border: 1px solid var(--border); - border-radius: var(--radius); - overflow: auto; -} - -@media (max-width: 980px) { - .admin-shell { flex-direction: column; height: auto; min-height: 100vh; } - .admin-nav { - width: 100%; - flex-direction: row; - overflow-x: auto; - padding-bottom: 0; - } - .admin-nav-header { min-width: 180px; margin-bottom: 0; border-bottom: 0; border-right: 1px solid var(--border); } - .admin-nav-item { white-space: nowrap; border-left: 0; border-bottom: 3px solid transparent; } - .admin-nav-item.active { border-bottom-color: var(--accent); border-left-color: transparent; } - .admin-toolbar { position: static; justify-content: flex-start; margin: 16px 20px 0; } - .admin-content { padding-top: 12px; } -} \ No newline at end of file diff --git a/site/info/themes/localfirst/icon.png b/site/info/themes/localfirst/icon.png deleted file mode 100644 index 22994d8..0000000 Binary files a/site/info/themes/localfirst/icon.png and /dev/null differ diff --git a/site/info/themes/localfirst/img/local_first_logo.png b/site/info/themes/localfirst/img/local_first_logo.png deleted file mode 100644 index 22994d8..0000000 Binary files a/site/info/themes/localfirst/img/local_first_logo.png and /dev/null differ diff --git a/site/info/themes/localfirst/page.html.uce b/site/info/themes/localfirst/page.html.uce deleted file mode 100644 index 5a7771c..0000000 --- a/site/info/themes/localfirst/page.html.uce +++ /dev/null @@ -1,54 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - String current_path = context.var["starter"]["route"]["l_path"].to_string(); - - DTree global_props; - global_props["cookie_consent"].set_bool(false); - - DTree account_props; - account_props["wrapper_class"] = "admin-account-card"; - account_props["links_wrapper_class"] = "admin-account-links"; - account_props["name_class"] = "admin-account-name"; - - <> - - "> - - - - "> - -
- -
- -
- -
- -
- -
-
-
- - - -} diff --git a/site/info/themes/portal-dark/css/style.css b/site/info/themes/portal-dark/css/style.css deleted file mode 100644 index 90001c3..0000000 --- a/site/info/themes/portal-dark/css/style.css +++ /dev/null @@ -1,313 +0,0 @@ -:root { - --bg-color: #0f172a; - --bg-secondary: #1e293b; - --surface: #1e293b; - --surface-elevated: #334155; - --surface-hover: #475569; - --primary: #60a5fa; - --primary-dark: #3b82f6; - --primary-light: #93c5fd; - --secondary: #a78bfa; - --accent: #22d3ee; - --text-primary: #f1f5f9; - --text-secondary: #cbd5e1; - --text-muted: #94a3b8; - --border: #334155; - --border-hover: #475569; - --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3); - --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3); - --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3); - --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.4); - --radius: 8px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-xl: 16px; - --radius-sm: 4px; - --glass-bg: rgba(30, 41, 59, 0.8); - --success: #10b981; - --success-bg: rgba(16, 185, 129, 0.1); - --success-border: rgba(16, 185, 129, 0.3); - --success-text: #10b981; - --warning: #f59e0b; - --warning-bg: rgba(245, 158, 11, 0.1); - --warning-border: rgba(245, 158, 11, 0.3); - --warning-text: #f59e0b; - --error: #ef4444; - --error-bg: rgba(239, 68, 68, 0.1); - --error-border: rgba(239, 68, 68, 0.3); - --error-text: #ef4444; - --info: #3b82f6; - --info-bg: rgba(59, 130, 246, 0.1); - --info-border: rgba(59, 130, 246, 0.3); - --info-text: #3b82f6; - --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - --font-mono: 'SFMono-Regular', Consolas, monospace; -} - -* { margin: 0; padding: 0; box-sizing: border-box; } -html { font-size: 16px; scroll-behavior: smooth; } -body { - font-family: var(--font-sans); - font-size: 1rem; - line-height: 1.6; - color: var(--text-primary); - background: var(--bg-color); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -a { color: var(--primary); text-decoration: none; transition: all 0.2s ease; } -a:hover { color: var(--primary-light); text-decoration: underline; } - -::selection { - background: rgba(96, 165, 250, 0.3); - color: var(--text-primary); -} - -body::before { - content: ''; - position: fixed; - inset: 0; - background: - radial-gradient(ellipse 80% 50% at 20% -10%, rgba(96, 165, 250, 0.05) 0%, transparent 60%), - radial-gradient(ellipse 60% 40% at 85% 110%, rgba(34, 211, 238, 0.04) 0%, transparent 50%); - pointer-events: none; - z-index: 0; -} - -nav { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 1000; - background: var(--glass-bg); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - border-bottom: 1px solid var(--border); - padding: 0 1rem; - display: flex; - align-items: center; - box-shadow: var(--shadow-sm); - transition: all 0.3s ease; -} -nav::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 1px; - background: linear-gradient(90deg, transparent, var(--primary), var(--accent), transparent); - opacity: 0.3; -} - -.nav-menu { display: flex; align-items: center; gap: 0.25rem; } -.nav-menu a, -.nav-account a { - display: inline-flex; - align-items: center; - padding: 0.5rem 0.75rem; - border-radius: var(--radius); - color: var(--text-primary); - text-decoration: none; -} -.nav-menu > a:first-child { - font-weight: 700; - color: var(--primary); - padding: 1rem 1.5rem; - margin: 0.5rem 0.25rem; -} -.nav-menu a:hover, -.nav-account a:hover { - background: var(--surface-hover); - color: var(--primary); -} -.nav-account { - margin-left: auto; - display: flex; - align-items: center; - gap: 0.5rem; -} -.nav-account .account-name { - color: var(--text-secondary); - font-weight: 500; - font-size: 0.95rem; - margin-right: 0.5rem; -} -.nav-account .nav-avatar, -.profile-avatar { - border-radius: 999px; - object-fit: cover; - border: 1px solid var(--border); -} -.nav-account .nav-avatar { width: 30px; height: 30px; } -.profile-avatar { width: 96px; height: 96px; } - -#content { - margin-top: 5rem; - min-height: calc(100vh - 10rem); - padding: 2rem 1rem; - max-width: 1200px; - margin-left: auto; - margin-right: auto; -} - -h1, h2, h3, h4, h5, h6 { - font-weight: 700; - line-height: 1.2; - margin-bottom: 1rem; - color: var(--text-primary); -} -h1 { - font-size: 2rem; - position: relative; - padding-bottom: 0.75rem; - margin-bottom: 1.25rem; -} -h1::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 60px; - height: 3px; - background: linear-gradient(90deg, var(--primary), var(--accent)); - border-radius: 3px; -} -h2 { font-size: 2rem; } -h3 { font-size: 1.5rem; } - -#content > div:not(.ws-app), .block, .card, .dashboard-panel { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - padding: 1.75rem; - margin-bottom: 1.5rem; - box-shadow: var(--shadow-sm); - transition: border-color 0.25s ease, box-shadow 0.25s ease; -} - -#content > div:not(.ws-app):hover, .block:hover, .card:hover, .dashboard-panel:hover { - box-shadow: var(--shadow-md); - border-color: var(--border-hover); -} - -form { max-width: 600px; margin: 0 auto; } -form > div { display: flex; flex-direction: column; margin-bottom: 1.5rem; gap: 0.5rem; } -label { font-weight: 500; color: var(--text-secondary); font-size: 0.875rem; text-transform: uppercase; letter-spacing: 0.05em; } -input, select, textarea { - width: 100%; - padding: 0.75rem 1rem; - border: 2px solid var(--border); - border-radius: var(--radius); - background: var(--bg-secondary); - color: var(--text-primary); - font-size: 1rem; - font-family: inherit; -} -textarea { min-height: 120px; } -input:focus, select:focus, textarea:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.2); - background: var(--surface); -} -button, .btn, input[type="submit"] { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0.75rem 1.5rem; - background: var(--primary); - color: var(--bg-color); - border: none; - border-radius: var(--radius); - font-weight: 600; - font-size: 1rem; - cursor: pointer; - transition: all 0.2s ease; -} -button:hover, .btn:hover, input[type="submit"]:hover { - background: var(--primary-dark); - transform: translateY(-1px); - box-shadow: var(--shadow-lg); - text-decoration: none; -} - -.banner { - border-radius: var(--radius); - padding: 0.8rem 1rem; - border: 1px solid var(--border); - margin-bottom: 1rem; - background: rgba(255,255,255,0.03); -} -.banner.success { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); } -.banner.warning { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning-text); } -.banner.error, .error { background: var(--error-bg); border-color: var(--error-border); color: var(--error-text); } - -table { - width: 100%; - border-collapse: collapse; - border: 1px solid var(--border); - background: rgba(255,255,255,0.02); - border-radius: var(--radius); - overflow: hidden; -} -th, td { padding: 0.8rem 0.9rem; border-bottom: 1px solid var(--border); text-align: left; } -th { background: var(--surface-elevated); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; } -tr:last-child td { border-bottom: none; } -tr:hover td { background: rgba(255,255,255,0.02); } -code, pre { font-family: var(--font-mono); } -pre { - padding: 1rem; - background: rgba(15, 23, 42, 0.55); - border: 1px solid var(--border); - border-radius: var(--radius); - overflow: auto; -} - -footer { - border-top: 1px solid var(--border); - padding: 1.25rem 1rem; - color: var(--text-muted); - font-size: 0.875rem; - background: rgba(15, 23, 42, 0.6); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); -} - -input[type="range"] { - width: 100%; - height: 6px; - background: var(--bg-secondary); - outline: none; - border: none; - border-radius: 999px; - -webkit-appearance: none; - appearance: none; -} -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - width: 18px; - height: 18px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - box-shadow: 0 0 6px rgba(96, 165, 250, 0.3); -} -input[type="range"]::-moz-range-thumb { - width: 18px; - height: 18px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - border: none; - box-shadow: 0 0 6px rgba(96, 165, 250, 0.3); -} - -@media (max-width: 860px) { - nav { flex-wrap: wrap; padding-bottom: 0.6rem; } - .nav-account { width: 100%; margin-left: 0; justify-content: flex-start; } - #content { margin-top: 7.5rem; padding: 1rem 0.75rem; } - #content > div:not(.ws-app), .block, .card, .dashboard-panel { padding: 1.25rem; margin-bottom: 1rem; } - h1 { font-size: 2rem; padding: 1.25rem; } -} \ No newline at end of file diff --git a/site/info/themes/portal-dark/icon.png b/site/info/themes/portal-dark/icon.png deleted file mode 100644 index 8a42581..0000000 Binary files a/site/info/themes/portal-dark/icon.png and /dev/null differ diff --git a/site/info/themes/portal-dark/page.html.uce b/site/info/themes/portal-dark/page.html.uce deleted file mode 100644 index 3f353a7..0000000 --- a/site/info/themes/portal-dark/page.html.uce +++ /dev/null @@ -1,31 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - - DTree nav_props; - nav_props["account_wrapper_class"] = "nav-account nav-menu"; - - DTree footer_props; - footer_props["embed_mode"].set_bool(embed_mode); - - <> - - "> - - - - "> - - -
> - -
- - - - -} diff --git a/site/info/themes/portal-light/css/style.css b/site/info/themes/portal-light/css/style.css deleted file mode 100644 index 141b15f..0000000 --- a/site/info/themes/portal-light/css/style.css +++ /dev/null @@ -1,392 +0,0 @@ -@font-face { - font-family: "B612"; - src: url("../../common/fonts/b612/b612-regular.ttf") format("truetype"); - font-style: normal; - font-weight: 400; - font-display: swap; -} -@font-face { - font-family: "B612"; - src: url("../../common/fonts/b612/b612-italic.ttf") format("truetype"); - font-style: italic; - font-weight: 400; - font-display: swap; -} -@font-face { - font-family: "B612"; - src: url("../../common/fonts/b612/b612-bold.ttf") format("truetype"); - font-style: normal; - font-weight: 700; - font-display: swap; -} -@font-face { - font-family: "B612 Mono"; - src: url("../../common/fonts/b612/b612-mono-regular.ttf") format("truetype"); - font-style: normal; - font-weight: 400; - font-display: swap; -} -@font-face { - font-family: "B612 Mono"; - src: url("../../common/fonts/b612/b612-mono-bold.ttf") format("truetype"); - font-style: normal; - font-weight: 700; - font-display: swap; -} - -:root { - --kg-blue: #0f68ad; - --kg-blue-dark: #0b4f85; - --kg-blue-light: #2d86ca; - --kg-bg: #e9e9ea; - --kg-surface: #ffffff; - --kg-border: rgba(0, 0, 0, 0.2); - --kg-text: #121417; - --kg-muted: #6c737b; - --kg-orange: #f08a00; - --kg-success: #149b2e; - --kg-danger: #e11818; - --topbar-height: 56px; - --bg-color: var(--kg-bg); - --bg-secondary: #ffffff; - --surface: var(--kg-surface); - --surface-elevated: #ffffff; - --surface-hover: #e8eef3; - --primary: var(--kg-blue); - --primary-dark: var(--kg-blue-dark); - --primary-light: var(--kg-blue-light); - --secondary: #596572; - --accent: var(--kg-orange); - --text-primary: var(--kg-text); - --text-secondary: #4b5560; - --text-muted: var(--kg-muted); - --border: var(--kg-border); - --border-hover: rgba(15, 104, 173, 0.3); - --success: var(--kg-success); - --success-bg: #e7f5ea; - --success-border: #86c88f; - --success-text: #0f6e22; - --warning: #c97a14; - --warning-bg: #fff4e4; - --warning-border: #f0c07b; - --warning-text: #92550a; - --error: var(--kg-danger); - --error-bg: #ffe7e7; - --error-border: #ea9999; - --error-text: #b80f0f; - --info: var(--primary); - --info-bg: #e8f2ff; - --info-border: #b9d4f3; - --info-text: #0b4f85; - --shadow-sm: 0 1px 2px rgba(18, 20, 23, 0.06); - --shadow-md: 0 8px 22px rgba(18, 20, 23, 0.06); - --shadow-lg: 0 16px 34px rgba(18, 20, 23, 0.1); - --shadow-xl: 0 20px 40px rgba(18, 20, 23, 0.14); - --radius: 8px; - --radius-sm: 6px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-xl: 16px; - --font-sans: "B612", "Segoe UI", sans-serif; - --font-mono: "B612 Mono", "SFMono-Regular", Consolas, monospace; -} - -* { box-sizing: border-box; margin: 0; padding: 0; } -html, body { min-height: 100%; } -body { - font-family: var(--font-sans); - font-size: 14px; - line-height: 1.4; - color: var(--text-primary); - background: var(--bg-color); -} -a { color: var(--primary-dark); text-decoration: none; } -a:hover { text-decoration: underline; } - -nav { - position: fixed; - top: 0; - left: 0; - right: 0; - height: var(--topbar-height); - display: flex; - align-items: stretch; - background: var(--primary); - border-bottom: 1px solid var(--primary-dark); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12); - z-index: 60; -} - -.nav-menu { - display: flex; - align-items: stretch; - overflow-x: auto; - white-space: nowrap; - flex: 1; -} - -.nav-menu > a { - display: inline-flex; - align-items: center; - padding: 0 0.9rem; - color: #fff; - border-right: 1px solid rgba(255, 255, 255, 0.16); - font-size: 14px; - font-weight: 700; - text-decoration: none; - background: transparent; -} - -.nav-menu > a:first-child { - font-size: 18px; - min-width: 250px; - background: rgba(0, 0, 0, 0.08); -} - -.nav-menu > a:hover, -.nav-menu > a:focus { - background: var(--primary-dark); - text-decoration: none; -} - -.nav-account { - display: flex; - align-items: center; - gap: 0.45rem; - padding: 0 0.7rem; - border-left: 1px solid rgba(255, 255, 255, 0.2); - background: rgba(0, 0, 0, 0.12); - flex-shrink: 0; -} - -.nav-account .account-name { - color: #d8f8df; - font-size: 14px; - font-weight: 700; -} - -.nav-account .nav-avatar, -.profile-avatar { - border-radius: 999px; - object-fit: cover; - border: 1px solid rgba(255, 255, 255, 0.4); -} - -.nav-account .nav-avatar { - width: 30px; - height: 30px; -} - -.profile-avatar { - width: 96px; - height: 96px; - border-color: var(--border); -} - -.nav-account a { - color: #fff; - font-size: 14px; - font-weight: 700; - padding: 0.22rem 0.5rem; - border-radius: 3px; -} - -.nav-account a:hover { - background: rgba(255, 255, 255, 0.16); - text-decoration: none; -} - -#content { - margin-top: var(--topbar-height); - padding: 1rem; - min-height: calc(100vh - var(--topbar-height)); -} - -#content > div:not(.ws-app), -.block, -.card, -.dashboard-panel { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - box-shadow: var(--shadow-sm); - padding: 1.25rem; - margin-bottom: 1rem; - transition: box-shadow 0.2s ease, border-color 0.2s ease; -} - -#content > div:not(.ws-app):hover, -.block:hover, -.card:hover, -.dashboard-panel:hover { - box-shadow: var(--shadow-md); - border-color: rgba(15, 104, 173, 0.2); -} - -h1, h2, h3, h4, h5, h6 { - font-weight: 700; - color: #252b31; - margin-bottom: 0.7rem; -} -h1 { font-size: 22px; padding-bottom: 0.5rem; border-bottom: 2px solid #d2d3d7; position: relative; } -h1::after { - content: ''; - position: absolute; - bottom: -2px; - left: 0; - width: 50px; - height: 2px; - background: var(--primary); - border-radius: 2px; -} -h2 { font-size: 18px; } -h3 { font-size: 16px; } -h4, h5, h6 { font-size: 14px; } - -p { margin: 0.4rem 0 0.85rem; } - -form { max-width: 780px; } -form > div { margin-bottom: 0.8rem; } -label { - display: block; - font-weight: 700; - font-size: 14px; - color: #3f464f; - margin-bottom: 0.3rem; -} -input, select, textarea { - width: 100%; - min-height: 36px; - padding: 0 0.7rem; - border: 1px solid #a8aaaf; - border-radius: 4px; - background: #fff; - color: var(--text-primary); - font-size: 14px; - font-family: inherit; -} -textarea { min-height: 100px; padding: 0.5rem 0.7rem; } -input:focus, select:focus, textarea:focus { - outline: none; - border-color: var(--primary-light); - box-shadow: 0 0 0 1px var(--primary-light); -} -button, .btn, input[type="submit"] { - display: inline-flex; - align-items: center; - justify-content: center; - min-height: 34px; - padding: 0 0.9rem; - border: 1px solid #7f8084; - border-radius: 4px; - background: #f7f7f7; - color: #1a1e23; - font-size: 14px; - font-weight: 700; - cursor: pointer; - font-family: inherit; -} -button:hover, .btn:hover, input[type="submit"]:hover { background: #ececef; text-decoration: none; } -button:active, .btn:active { transform: translateY(1px); } - -.banner { - border-radius: 4px; - padding: 0.65rem 0.8rem; - border: 1px solid #b4b5ba; - margin-bottom: 0.8rem; - background: #fafafa; -} -.banner.success { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); } -.banner.warning { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning-text); } -.banner.error, .error { background: var(--error-bg); border-color: var(--error-border); color: var(--error-text); } - -table { - width: 100%; - border-collapse: collapse; - background: var(--bg-secondary); - border: 1px solid var(--border); - border-radius: var(--radius); - overflow: hidden; -} -th, td { - padding: 0.7rem 0.8rem; - border-bottom: 1px solid var(--border); - text-align: left; - vertical-align: top; -} -th { background: #e7e7e8; font-size: 13px; text-transform: uppercase; letter-spacing: 0.04em; } -tr:last-child td { border-bottom: none; } -tr:hover td { background: rgba(0, 0, 0, 0.02); } - -code, pre { font-family: var(--font-mono); } -pre { - padding: 0.9rem; - background: #fff; - border: 1px solid var(--border); - border-radius: var(--radius); - overflow: auto; -} - -footer { - border-top: 1px solid var(--border); - background: #ffffff; - color: var(--text-muted); - padding: 1rem 1rem 1.5rem; - font-size: 13px; -} -.footer-inner { max-width: 1200px; margin: 0 auto; } - -input[type="range"] { - height: 6px; - padding: 0; - min-height: auto; - border: none; - background: #d4d5d9; - border-radius: 999px; - -webkit-appearance: none; - appearance: none; -} -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - width: 18px; - height: 18px; - background: var(--primary); - border-radius: 50%; - cursor: pointer; - box-shadow: 0 1px 3px rgba(0,0,0,0.2); -} -input[type="range"]::-moz-range-thumb { - width: 18px; - height: 18px; - background: var(--primary); - border-radius: 50%; - cursor: pointer; - border: none; - box-shadow: 0 1px 3px rgba(0,0,0,0.2); -} - -::selection { - background: rgba(15, 104, 173, 0.2); - color: var(--text-primary); -} - -@media (max-width: 860px) { - nav { - height: auto; - flex-direction: column; - } - .nav-menu { - flex-wrap: wrap; - } - .nav-menu > a:first-child { - min-width: 0; - } - .nav-account { - justify-content: flex-start; - padding: 0.6rem 0.7rem; - } - #content { - margin-top: 104px; - padding: 0.75rem; - } -} \ No newline at end of file diff --git a/site/info/themes/portal-light/icon.png b/site/info/themes/portal-light/icon.png deleted file mode 100644 index 8a42581..0000000 Binary files a/site/info/themes/portal-light/icon.png and /dev/null differ diff --git a/site/info/themes/portal-light/page.html.uce b/site/info/themes/portal-light/page.html.uce deleted file mode 100644 index d125df0..0000000 --- a/site/info/themes/portal-light/page.html.uce +++ /dev/null @@ -1,29 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - - DTree footer_props; - footer_props["embed_mode"].set_bool(embed_mode); - footer_props["inner_class"] = "footer-inner"; - - <> - - "> - - - - "> - - -
> - -
- - - - -} diff --git a/site/info/themes/retro-gaming/css/style.css b/site/info/themes/retro-gaming/css/style.css deleted file mode 100644 index f187fa6..0000000 --- a/site/info/themes/retro-gaming/css/style.css +++ /dev/null @@ -1,523 +0,0 @@ -/* ──────────────────────────────────────────────────────── - RETRO GAMING THEME - CRT scanlines · pixel font · neon glow · 8-bit palette - ──────────────────────────────────────────────────────── */ - -@font-face { - font-family: 'Press Start 2P'; - src: url('../../common/fonts/press-start-2p/press-start-2p-regular.ttf') format('truetype'); - font-style: normal; - font-weight: 400; - font-display: swap; -} - -/* ── tokens ─────────────────────────────────────────── */ -:root { - /* background */ - --bg-color: #0a0a1a; - --bg-secondary: #10102a; - --surface: #12122e; - --surface-elevated: #1a1a3e; - --surface-hover: #22224e; - - /* neon palette */ - --primary: #00ff88; - --primary-dark: #00cc6a; - --primary-light: #66ffbb; - --secondary: #ff00ff; - --accent: #ffff00; - --text-primary: #e0e0ff; - --text-secondary: #a0a0cc; - --text-muted: #6868a0; - - /* borders, shadows */ - --border: #2a2a5a; - --border-hover: #3a3a7a; - --shadow-sm: 0 2px 0 #000; - --shadow-md: 0 4px 0 #000, 0 0 12px rgba(0, 255, 136, 0.08); - --shadow-lg: 0 6px 0 #000, 0 0 24px rgba(0, 255, 136, 0.12); - --shadow-xl: 0 8px 0 #000, 0 0 40px rgba(0, 255, 136, 0.16); - - /* semantic */ - --success: #00ff88; - --success-bg: rgba(0, 255, 136, 0.1); - --success-border: rgba(0, 255, 136, 0.3); - --success-text: #00ff88; - --warning: #ffff00; - --warning-bg: rgba(255, 255, 0, 0.1); - --warning-border: rgba(255, 255, 0, 0.3); - --warning-text: #ffff00; - --error: #ff3366; - --error-bg: rgba(255, 51, 102, 0.1); - --error-border: rgba(255, 51, 102, 0.3); - --error-text: #ff3366; - --info: #00ccff; - --info-bg: rgba(0, 204, 255, 0.1); - --info-border: rgba(0, 204, 255, 0.3); - --info-text: #00ccff; - - /* geometry */ - --radius: 0px; - --radius-sm: 0px; - --radius-md: 0px; - --radius-lg: 2px; - --radius-xl: 4px; - - /* typography */ - --font-sans: 'Press Start 2P', monospace; - --font-mono: 'Press Start 2P', monospace; -} - -/* ── reset ──────────────────────────────────────────── */ -* { margin: 0; padding: 0; box-sizing: border-box; } -html { font-size: 16px; scroll-behavior: smooth; image-rendering: pixelated; } - -body { - font-family: var(--font-sans); - font-size: 10px; - line-height: 2; - color: var(--text-primary); - background: var(--bg-color); - -webkit-font-smoothing: none; - -moz-osx-font-smoothing: unset; -} - -/* ── CRT scanline overlay ───────────────────────────── */ -body::before { - content: ''; - position: fixed; - inset: 0; - background: repeating-linear-gradient( - 0deg, - transparent, - transparent 2px, - rgba(0, 0, 0, 0.15) 2px, - rgba(0, 0, 0, 0.15) 4px - ); - pointer-events: none; - z-index: 9000; -} - -/* subtle vignette */ -body::after { - content: ''; - position: fixed; - inset: 0; - background: radial-gradient(ellipse at center, transparent 60%, rgba(0, 0, 0, 0.5) 100%); - pointer-events: none; - z-index: 8999; -} - -::selection { - background: var(--primary); - color: var(--bg-color); -} - -/* ── links ──────────────────────────────────────────── */ -a { - color: var(--primary); - text-decoration: none; - transition: color 0.1s step-end; -} -a:hover { - color: var(--accent); - text-decoration: none; - text-shadow: 0 0 6px var(--accent); -} - -/* ── navigation ─────────────────────────────────────── */ -nav { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 1000; - background: var(--bg-secondary); - border-bottom: 3px solid var(--primary); - padding: 0 0.5rem; - display: flex; - align-items: center; - box-shadow: 0 3px 0 #000, 0 6px 20px rgba(0, 255, 136, 0.15); -} - -.nav-menu { - display: flex; - align-items: center; - gap: 0; - flex: 1; - min-width: 0; - overflow-x: auto; - scrollbar-width: none; -} -.nav-menu::-webkit-scrollbar { display: none; } - -.nav-menu a, -.nav-account a { - display: inline-flex; - align-items: center; - padding: 0.75rem 0.8rem; - color: var(--text-secondary); - text-decoration: none; - font-size: 8px; - letter-spacing: 0.5px; - text-transform: uppercase; - border-right: 1px solid var(--border); - transition: background 0.1s step-end, color 0.1s step-end; -} - -.nav-menu > a:first-child { - color: var(--primary); - text-shadow: 0 0 8px rgba(0, 255, 136, 0.5); - font-size: 10px; - padding: 0.75rem 1rem; - border-right: 2px solid var(--primary); -} - -.nav-menu a:hover, -.nav-account a:hover { - background: var(--surface-hover); - color: var(--accent); - text-shadow: 0 0 6px var(--accent); - text-decoration: none; -} - -.nav-account { - margin-left: auto; - display: flex; - align-items: center; - gap: 0; - flex: 0 0 auto; - overflow: visible; -} -.nav-account a { - border-right: none; - border-left: 1px solid var(--border); -} - -.nav-account .account-name { - color: var(--primary); - font-size: 8px; - padding: 0 0.5rem; -} - -.nav-account .nav-avatar, -.profile-avatar { - border-radius: 0; - border: 2px solid var(--primary); - image-rendering: pixelated; -} -.nav-account .nav-avatar { width: 24px; height: 24px; } -.profile-avatar { width: 64px; height: 64px; } - -/* ── main content ───────────────────────────────────── */ -#content { - margin-top: 3.5rem; - min-height: calc(100vh - 7rem); - padding: 1.5rem 1rem; - max-width: 1100px; - margin-left: auto; - margin-right: auto; - position: relative; - z-index: 1; -} - -/* ── typography ─────────────────────────────────────── */ -h1, h2, h3, h4, h5, h6 { - font-weight: 400; - line-height: 2; - margin-bottom: 0.75rem; - color: var(--primary); - text-shadow: 0 0 10px rgba(0, 255, 136, 0.35); - text-transform: uppercase; -} - -h1 { - font-size: 16px; - padding: 0.75rem 0; - border-bottom: 3px double var(--primary); - margin-bottom: 1.25rem; - position: relative; -} -h1::before { - content: '►'; - margin-right: 0.5rem; - animation: blink-cursor 1s step-end infinite; -} -h2 { font-size: 12px; color: var(--info-text); text-shadow: 0 0 8px rgba(0, 204, 255, 0.3); } -h3 { font-size: 10px; color: var(--secondary); text-shadow: 0 0 8px rgba(255, 0, 255, 0.3); } -h4, h5, h6 { font-size: 10px; } - -p { margin: 0 0 0.75rem; } - -@keyframes blink-cursor { - 0%, 100% { opacity: 1; } - 50% { opacity: 0; } -} - -/* ── cards / blocks ─────────────────────────────────── */ -#content > div:not(.ws-app):not(.demo-section), -.block, -.card, -.dashboard-panel { - background: var(--surface); - border: 2px solid var(--border); - padding: 1rem; - margin-bottom: 1.25rem; - box-shadow: var(--shadow-md); - position: relative; - transition: border-color 0.1s step-end; -} - -#content > div:not(.ws-app):not(.demo-section)::before, -.block::before, -.card::before, -.dashboard-panel::before { - content: ''; - position: absolute; - top: 0; left: 0; right: 0; - height: 2px; - background: linear-gradient(90deg, var(--primary), var(--secondary), var(--accent)); -} - -#content > div:not(.ws-app):not(.demo-section):hover, -.block:hover, -.card:hover, -.dashboard-panel:hover { - border-color: var(--border-hover); - box-shadow: var(--shadow-lg); -} - -/* ── forms ──────────────────────────────────────────── */ -form { max-width: 640px; } -form > div { display: grid; gap: 0.35rem; margin-bottom: 1rem; } - -label { - color: var(--accent); - font-size: 8px; - text-transform: uppercase; - letter-spacing: 1px; -} - -input, select, textarea { - width: 100%; - padding: 0.6rem 0.7rem; - border: 2px solid var(--border); - background: var(--bg-color); - color: var(--primary); - font-family: var(--font-mono); - font-size: 10px; - caret-color: var(--primary); -} -textarea { min-height: 100px; } - -input:focus, select:focus, textarea:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 1px var(--primary), 0 0 12px rgba(0, 255, 136, 0.2); -} - -input::placeholder, textarea::placeholder { - color: var(--text-muted); - opacity: 1; -} - -/* ── buttons ────────────────────────────────────────── */ -button, .btn, input[type="submit"] { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0.6rem 1.2rem; - border: 2px solid var(--primary); - background: transparent; - color: var(--primary); - font-family: var(--font-sans); - font-size: 9px; - text-transform: uppercase; - letter-spacing: 0.5px; - cursor: pointer; - transition: all 0.1s step-end; - box-shadow: 3px 3px 0 var(--bg-color), 4px 4px 0 var(--primary); -} - -button:hover, .btn:hover, input[type="submit"]:hover { - background: var(--primary); - color: var(--bg-color); - text-shadow: none; - box-shadow: 1px 1px 0 var(--bg-color), 2px 2px 0 var(--primary); - transform: translate(2px, 2px); - text-decoration: none; -} - -button:active, .btn:active, input[type="submit"]:active { - box-shadow: none; - transform: translate(4px, 4px); -} - -.btn-secondary { - border-color: var(--secondary); - color: var(--secondary); - box-shadow: 3px 3px 0 var(--bg-color), 4px 4px 0 var(--secondary); -} -.btn-secondary:hover { - background: var(--secondary); - color: var(--bg-color); - box-shadow: 1px 1px 0 var(--bg-color), 2px 2px 0 var(--secondary); -} - -.btn-outline { - border-color: var(--accent); - color: var(--accent); - box-shadow: 3px 3px 0 var(--bg-color), 4px 4px 0 var(--accent); -} -.btn-outline:hover { - background: var(--accent); - color: var(--bg-color); - box-shadow: 1px 1px 0 var(--bg-color), 2px 2px 0 var(--accent); -} - -/* ── range slider ───────────────────────────────────── */ -input[type="range"] { - height: 8px; - padding: 0; - border: 2px solid var(--border); - background: var(--bg-color); - -webkit-appearance: none; - appearance: none; -} -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - width: 14px; - height: 14px; - background: var(--primary); - border: 2px solid var(--bg-color); - cursor: pointer; - box-shadow: 0 0 6px rgba(0, 255, 136, 0.4); -} -input[type="range"]::-moz-range-thumb { - width: 14px; - height: 14px; - background: var(--primary); - border: 2px solid var(--bg-color); - border-radius: 0; - cursor: pointer; - box-shadow: 0 0 6px rgba(0, 255, 136, 0.4); -} - -/* ── banners ────────────────────────────────────────── */ -.banner { - padding: 0.6rem 0.8rem; - border: 2px solid var(--border); - margin-bottom: 0.75rem; - background: var(--surface); -} -.banner.success { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); } -.banner.warning { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning-text); } -.banner.error, .error { background: var(--error-bg); border-color: var(--error-border); color: var(--error-text); } - -/* ── tables ─────────────────────────────────────────── */ -table { - width: 100%; - border-collapse: collapse; - background: var(--surface); - border: 2px solid var(--border); -} -th, td { - padding: 0.5rem 0.65rem; - border-bottom: 1px solid var(--border); - text-align: left; - font-size: 9px; -} -th { - background: var(--surface-elevated); - color: var(--accent); - text-transform: uppercase; - letter-spacing: 0.5px; - border-bottom: 2px solid var(--accent); -} -tr:last-child td { border-bottom: none; } -tr:hover td { background: rgba(0, 255, 136, 0.04); } - -/* ── code ───────────────────────────────────────────── */ -code, pre { font-family: var(--font-mono); } -pre { - padding: 0.75rem; - background: var(--bg-color); - border: 2px solid var(--border); - overflow: auto; - color: var(--primary); -} - -/* ── footer ─────────────────────────────────────────── */ -footer { - border-top: 3px solid var(--primary); - padding: 1rem; - color: var(--text-muted); - font-size: 8px; - background: var(--bg-secondary); - box-shadow: 0 -3px 0 #000; - position: relative; - z-index: 1; -} -footer::before { - content: '// '; - color: var(--text-muted); -} - -/* ── pixel decoration classes (for page template) ──── */ -.retro-stars { - position: fixed; - inset: 0; - z-index: 0; - pointer-events: none; - background: - radial-gradient(1px 1px at 10% 15%, var(--primary), transparent), - radial-gradient(1px 1px at 30% 45%, var(--accent), transparent), - radial-gradient(1px 1px at 55% 20%, var(--secondary), transparent), - radial-gradient(1px 1px at 70% 65%, var(--info-text), transparent), - radial-gradient(1px 1px at 85% 30%, var(--primary), transparent), - radial-gradient(1px 1px at 15% 75%, var(--accent), transparent), - radial-gradient(1px 1px at 45% 85%, var(--secondary), transparent), - radial-gradient(1px 1px at 90% 80%, var(--primary), transparent), - radial-gradient(1px 1px at 25% 55%, var(--info-text), transparent), - radial-gradient(1px 1px at 60% 50%, var(--accent), transparent), - radial-gradient(1px 1px at 5% 40%, var(--error-text), transparent), - radial-gradient(1px 1px at 75% 10%, var(--accent), transparent), - radial-gradient(1px 1px at 40% 30%, var(--primary), transparent), - radial-gradient(1px 1px at 95% 55%, var(--secondary), transparent), - radial-gradient(1px 1px at 50% 70%, var(--primary), transparent), - radial-gradient(1px 1px at 20% 90%, var(--info-text), transparent); - animation: twinkle 4s ease-in-out infinite alternate; -} -@keyframes twinkle { - 0% { opacity: 0.4; } - 100% { opacity: 0.8; } -} - -/* ── responsive ─────────────────────────────────────── */ -@media (max-width: 860px) { - nav { flex-wrap: wrap; } - .nav-menu { overflow-x: auto; white-space: nowrap; } - .nav-account { - width: 100%; - margin-left: 0; - border-top: 1px solid var(--border); - justify-content: flex-start; - } - #content { margin-top: 5rem; padding: 1rem 0.75rem; } - h1 { font-size: 12px; } - h2 { font-size: 10px; } -} - -/* ── focus accessibility ────────────────────────────── */ -button:focus, .btn:focus, input:focus, textarea:focus, select:focus { - outline: 2px solid var(--primary); - outline-offset: 2px; -} - -/* ── print ──────────────────────────────────────────── */ -@media print { - nav, footer, .retro-stars { display: none; } - body::before, body::after { display: none; } - #content { margin-top: 0; } - * { background: white !important; color: black !important; box-shadow: none !important; text-shadow: none !important; } -} diff --git a/site/info/themes/retro-gaming/icon.png b/site/info/themes/retro-gaming/icon.png deleted file mode 100644 index 12dfe2c..0000000 Binary files a/site/info/themes/retro-gaming/icon.png and /dev/null differ diff --git a/site/info/themes/retro-gaming/page.html.uce b/site/info/themes/retro-gaming/page.html.uce deleted file mode 100644 index c0a53da..0000000 --- a/site/info/themes/retro-gaming/page.html.uce +++ /dev/null @@ -1,32 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - - DTree nav_props; - nav_props["account_wrapper_class"] = "nav-account nav-menu"; - - DTree footer_props; - footer_props["embed_mode"].set_bool(embed_mode); - - <> - - "> - - - - > -
- - -
> - -
- - - - -} diff --git a/site/info/uce-starter/README.md b/site/info/uce-starter/README.md deleted file mode 100644 index 991a46a..0000000 --- a/site/info/uce-starter/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# UCE Starter - -`site/examples/uce-starter/` is a UCE-native port of the PHP `web-app-starter/`. - -It keeps the PHP starter around as reference while mirroring the same broad structure: - -- `index.uce` as the front controller -- `views/` for routed page content -- `components/` for reusable UI building blocks -- `themes/`, `js/`, and `img/` for theme templates and static assets - -This port intentionally leans on UCE's component layer rather than treating components as a compatibility shim. The page shell, nav/footer chrome, theme switcher, dashboard blocks, workspace primitives, and marketing sections are all rendered through `component()`. - -Theme rendering is split the same way as the PHP starter: - -- `themes/common/page.blank.uce` -- `themes/common/page.json.uce` -- `themes//page.html.uce` - -Those page templates are the authoritative shell layer, and in the UCE port they are proper `COMPONENT(...)` units rather than standalone page entrypoints. `index.uce` resolves the routed view, captures the `main` fragment, then hands off once into `themes/common/page.*.uce` or `themes//page.html.uce`, matching the PHP starter's page-layer flow without an extra shell implementation. - -The example uses query-string routing in the same style as the PHP starter: - -- `index.uce` -- `index.uce?page1` -- `index.uce?themes&theme=portal-dark` -- `index.uce?workspace/projects` - -The demo account pages use a small file-backed user store under `/tmp/uce-starter-data/` with session-based login state. diff --git a/site/info/uce-starter/components/auth/oauth-client.uce b/site/info/uce-starter/components/auth/oauth-client.uce deleted file mode 100644 index 7439a78..0000000 --- a/site/info/uce-starter/components/auth/oauth-client.uce +++ /dev/null @@ -1,100 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - String title = first(context.call["title"].to_string(), "Sign in with OAuth"); - String subtitle = first(context.call["subtitle"].to_string(), "Choose your preferred authentication method"); - String callback_url = first(context.call["callback_url"].to_string(), starter_link("auth/callback", context)); - - DTree services = context.call["services"]; - if(services.get_type_name() != "array" || services["google"]["name"].to_string() == "") - { - services["google"]["name"] = "Google"; - services["google"]["color"] = "#4285f4"; - services["google"]["icon"] = "fab fa-google"; - services["google"]["scope"] = "openid email profile"; - services["google"]["auth_url"] = "https://accounts.google.com/o/oauth2/v2/auth"; - - services["github"]["name"] = "GitHub"; - services["github"]["color"] = "#333333"; - services["github"]["icon"] = "fab fa-github"; - services["github"]["scope"] = "user:email"; - services["github"]["auth_url"] = "https://github.com/login/oauth/authorize"; - - services["discord"]["name"] = "Discord"; - services["discord"]["color"] = "#5865f2"; - services["discord"]["icon"] = "fab fa-discord"; - services["discord"]["scope"] = "identify email"; - services["discord"]["auth_url"] = "https://discord.com/api/oauth2/authorize"; - - services["twitch"]["name"] = "Twitch"; - services["twitch"]["color"] = "#9146ff"; - services["twitch"]["icon"] = "fab fa-twitch"; - services["twitch"]["scope"] = "user:read:email"; - services["twitch"]["auth_url"] = "https://id.twitch.tv/oauth2/authorize"; - } - - <> - -
-

- -
-
- - - - -
- - - -} diff --git a/site/info/uce-starter/components/basic/cookie-consent.uce b/site/info/uce-starter/components/basic/cookie-consent.uce deleted file mode 100644 index 05bfa76..0000000 --- a/site/info/uce-starter/components/basic/cookie-consent.uce +++ /dev/null @@ -1,114 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - - <> - - - -} diff --git a/site/info/uce-starter/components/data/widgets.uce b/site/info/uce-starter/components/data/widgets.uce deleted file mode 100644 index fa25082..0000000 --- a/site/info/uce-starter/components/data/widgets.uce +++ /dev/null @@ -1,308 +0,0 @@ -#load "../../lib/app.uce" - -String data_format_bytes(String raw, bool disk = false) -{ - if(trim(raw) == "") - return("--"); - StringList units; - units.push_back("B"); - units.push_back("KB"); - units.push_back("MB"); - units.push_back("GB"); - units.push_back("TB"); - units.push_back("PB"); - f64 value = atof(raw.c_str()); - u32 unit_index = 0; - while((value >= 1024.0 || value <= -1024.0) && unit_index < units.size() - 1) - { - value /= 1024.0; - unit_index += 1; - } - u32 decimals = disk ? (unit_index >= 4 ? 2 : (unit_index >= 1 ? 1 : 0)) : (unit_index == 0 ? 0 : 1); - char buf[64]; - snprintf(buf, sizeof(buf), ("%." + std::to_string(decimals) + "f").c_str(), value); - return(String(buf) + " " + units[unit_index]); -} - -DTree data_format_value(DTree value, DTree row, DTree column) -{ - DTree result; - String format = column["format"].to_string(); - String raw = value.to_string(); - String sort_value = raw; - String display_value = raw; - if(format == "number") - { - display_value = raw; - } - else if(format == "bytes") - { - display_value = data_format_bytes(raw, false); - } - else if(format == "disk-bytes") - { - display_value = data_format_bytes(raw, true); - } - else if(format == "percent") - { - display_value = raw + "%"; - } - else if(format == "duration-ms") - { - f64 number = atof(raw.c_str()); - if(number >= 1000.0) - { - char buf[64]; - snprintf(buf, sizeof(buf), number >= 10000.0 ? "%.0f s" : "%.1f s", number / 1000.0); - display_value = buf; - } - else - { - char buf[64]; - snprintf(buf, sizeof(buf), number >= 100.0 ? "%.0f ms" : "%.1f ms", number); - display_value = buf; - } - } - else if(format == "bool") - { - bool on = raw == "1" || to_lower(raw) == "true" || to_lower(raw) == "yes"; - display_value = on ? "Yes" : "No"; - sort_value = on ? "1" : "0"; - } - result["display"] = display_value; - result["sort"] = sort_value; - return(result); -} - -COMPONENT:SUMMARY_METRICS(Request& context) -{ - String title = context.call["title"].to_string(); - String subtitle = context.call["subtitle"].to_string(); - - <> -
- -
-

-

-
- -
- < class="dashboard-stat-card tone-"> -
-
-
- > -
-
- -} - -COMPONENT:TIMESERIES_CHART(Request& context) -{ - starter_register_js("js/u-format.js", context); - starter_register_js("js/u-timeseries-chart.js", context); - - String chart_id = first(context.call["id"].to_string(), "ts-chart-" + std::to_string((u64)time())); - String canvas_id = chart_id + "-canvas"; - String title = context.call["title"].to_string(); - String subtitle = context.call["subtitle"].to_string(); - s32 height = std::max(180, (s32)int_val(first(context.call["height"].to_string(), "320"))); - String x_axis_label = first(context.call["x_axis_label"].to_string(), "Time"); - String y_axis_left_label = first(context.call["y_axis_left_label"].to_string(), "Value"); - String y_axis_right_label = context.call["y_axis_right_label"].to_string(); - String y_axis_left_format = first(context.call["y_axis_left_format"].to_string(), "number"); - String y_axis_right_format = first(context.call["y_axis_right_format"].to_string(), "number"); - - <> -
- -
-

-

-
- - -
- - -} - -COMPONENT:SORTABLE_TABLE(Request& context) -{ - starter_register_js("js/u-format.js", context); - starter_register_js("js/u-sortable-table.js", context); - - String table_id = first(context.call["id"].to_string(), "sortable-table-" + std::to_string((u64)time())); - String title = context.call["title"].to_string(); - String subtitle = context.call["subtitle"].to_string(); - String empty_label = first(context.call["empty_label"].to_string(), "No data available"); - - DTree init_options; - init_options["storageKey"] = first(context.call["storage_key"].to_string(), "starter.sort." + table_id); - if(context.call["sort"]["column"].to_string() != "") - { - init_options["initialSort"]["column"] = context.call["sort"]["column"]; - init_options["initialSort"]["direction"] = first(context.call["sort"]["direction"].to_string(), "asc"); - } - - <> -
- -
-

-

-
- -
-
>
" class="muted">
" class="muted">
" data-sort-value="">
- - - - - - - - - - - -
>
" class="muted">
" data-sort-value="">
-
-
- - -} - -COMPONENT:DATA_TABLE(Request& context) -{ - String table_id = first(context.call["id"].to_string(), "data-grid-" + std::to_string((u64)time())); - starter_register_js("js/ag-grid/ag-grid-community.min.js", context); - starter_register_css("js/ag-grid/ag-grid.css", context); - starter_register_css("js/ag-grid/ag-theme-alpine.css", context); - - DTree columns = context.call["columns"]; - if(columns.get_type_name() != "array") - columns.set_array(); - bool has_explicit_columns = columns.is_list() && - columns._map.size() > 0 && - columns._map.find("0") != columns._map.end() && - columns["0"]["field"].to_string() != ""; - if(!has_explicit_columns && context.call["items"]["0"].get_type_name() == "array") - { - context.call["items"]["0"].each([&](DTree value, String key) { - DTree col; - col["field"] = key; - col["headerName"] = key; - col["sortable"].set_bool(true); - col["filter"].set_bool(true); - col["resizable"].set_bool(true); - columns.push(col); - }); - } - if(!columns.is_list()) - { - DTree normalized_columns; - normalized_columns.set_array(); - columns.each([&](DTree column, String key) { - if(column.get_type_name() == "array") - normalized_columns.push(column); - }); - columns = normalized_columns; - } - - DTree row_data = context.call["items"]; - if(row_data.get_type_name() != "array") - row_data.set_array(); - if(!row_data.is_list()) - { - DTree normalized_rows; - normalized_rows.set_array(); - row_data.each([&](DTree row, String key) { - if(row.get_type_name() == "array") - normalized_rows.push(row); - }); - row_data = normalized_rows; - } - - DTree grid_options; - grid_options["pagination"].set_bool(true); - grid_options["paginationPageSize"] = first(context.call["options"]["paginationPageSize"].to_string(), "20"); - grid_options["paginationPageSizeSelector"].set_bool(false); - grid_options["suppressMenuHide"].set_bool(true); - grid_options["animateRows"].set_bool(true); - grid_options["columnDefs"] = columns; - grid_options["rowData"] = row_data; - - <> -
-
-
- rows - -
-
- - -
-
-
; width: 100%; border: 1px solid var(--border); border-radius: 0 0 0.5rem 0.5rem; overflow: hidden;">
-
- - -} diff --git a/site/info/uce-starter/components/example/marketing_blocks.uce b/site/info/uce-starter/components/example/marketing_blocks.uce deleted file mode 100644 index 5027036..0000000 --- a/site/info/uce-starter/components/example/marketing_blocks.uce +++ /dev/null @@ -1,604 +0,0 @@ -#load "../../lib/app.uce" - -void marketing_default_features(DTree& features) -{ - if(features.get_type_name() == "array" && features["0"]["title"].to_string() != "") - return; - DTree item; - - item["icon"] = "⚡"; - item["title"] = "Lightning Fast"; - item["description"] = "Optimized for speed and performance with modern web technologies."; - features.push(item); - item.clear(); - - item["icon"] = "🎨"; - item["title"] = "Beautiful Design"; - item["description"] = "Carefully crafted components with attention to detail and user experience."; - features.push(item); - item.clear(); - - item["icon"] = "📱"; - item["title"] = "Mobile First"; - item["description"] = "Fully responsive design that works perfectly on all devices."; - features.push(item); - item.clear(); - - item["icon"] = "🔧"; - item["title"] = "Easy to Use"; - item["description"] = "Simple and intuitive component system for rapid development."; - features.push(item); - item.clear(); - - item["icon"] = "🛡️"; - item["title"] = "Secure"; - item["description"] = "Built with security best practices and server-side rendering first."; - features.push(item); - item.clear(); - - item["icon"] = "🚀"; - item["title"] = "Scalable"; - item["description"] = "Architecture designed to grow with your application needs."; - features.push(item); -} - -COMPONENT:HERO_SECTION(Request& context) -{ - String title = first(context.call["title"].to_string(), "Welcome to the Present"); - String subtitle = first(context.call["subtitle"].to_string(), "Experience no-quite-modern web development with our cutting-edge framework"); - String cta_text = first(context.call["cta_text"].to_string(), "Get Started"); - String cta_link = first(context.call["cta_link"].to_string(), "#"); - - <> -
-
-

-

-
- - Learn More -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - - -} - -COMPONENT:FEATURES_GRID(Request& context) -{ - DTree features = context.call["features"]; - marketing_default_features(features); - - <> -
-
-

Why Choose Our Framework?

-

Discover the powerful features that make development a breeze

-
-
-
-
-

-

-
-
-
-
- - -} - -COMPONENT:STATS_SECTION(Request& context) -{ - DTree stats = context.call["stats"]; - if(stats.get_type_name() != "array" || stats["0"]["label"].to_string() == "") - { - DTree 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(); - item["number"] = "24/7"; item["label"] = "Support"; stats.push(item); - } - - <> -
-
-
-

Trusted by Developers Worldwide

-

Join thousands of developers who have chosen our framework

-
-
-
-
-
-
-
-
-
-
- - -} - -COMPONENT:BRANDS_SHOWCASE(Request& context) -{ - DTree logos = context.call["logos"]; - if(logos.get_type_name() != "array" || logos["0"]["name"].to_string() == "") - { - DTree item; - for(s32 i = 1; i <= 6; i++) - { - item["name"] = "Brand " + std::to_string(i); - item["url"] = "img/cat0" + std::to_string(i) + ".jpg"; - logos.push(item); - item.clear(); - } - } - String title = first(context.call["title"].to_string(), "Trusted by Leading Companies"); - - <> -
-
-

-
-
- " alt="" /> -
-
-
-
- - -} - -COMPONENT:TESTIMONIALS(Request& context) -{ - DTree testimonials = context.call["testimonials"]; - if(testimonials.get_type_name() != "array" || testimonials["0"]["name"].to_string() == "") - { - DTree 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); - } - - <> -
-
-
-

What Developers Say

-

Don't just take our word for it - hear from the community

-
-
-
-
-
"
-

-
-
-
- " alt="" class="avatar"> -
-
-
-
-
-
-
-
-
- - -} - -COMPONENT:PRICING_TABLE(Request& context) -{ - DTree plans = context.call["plans"]; - if(plans.get_type_name() != "array" || plans["0"]["name"].to_string() == "") - { - DTree plan; - DTree 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(); - plan["name"] = "Enterprise"; plan["price"] = "$99"; plan["period"] = "/mo"; plan["description"] = "For larger teams and custom deployments"; plan["cta"] = "Contact Sales"; feature = "Custom integrations"; plan["features"].push(feature); feature = "Dedicated support"; plan["features"].push(feature); feature = "Architecture help"; plan["features"].push(feature); plans.push(plan); - } - - <> -
-
-
-

Simple Pricing

-

Choose the plan that fits your product stage.

-
-
- -
- -
-
- - -} - -COMPONENT:CTA_SECTION(Request& context) -{ - String title = first(context.call["title"].to_string(), "Ready to Get Started?"); - String subtitle = first(context.call["subtitle"].to_string(), "Join thousands of developers building amazing applications with our framework."); - String cta_text = first(context.call["cta_text"].to_string(), "Start Building Now"); - String cta_link = first(context.call["cta_link"].to_string(), "#"); - String secondary_text = first(context.call["secondary_text"].to_string(), "View Documentation"); - String secondary_link = first(context.call["secondary_link"].to_string(), "#"); - - <> -
-
-
-

-

-
- - -
-
-
-
-
-
-
-
-
-
-
-
- - -} diff --git a/site/info/uce-starter/components/example/theme-switcher.uce b/site/info/uce-starter/components/example/theme-switcher.uce deleted file mode 100644 index 28f7de7..0000000 --- a/site/info/uce-starter/components/example/theme-switcher.uce +++ /dev/null @@ -1,153 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - String current_theme = context.cfg.get_by_path("theme/key").to_string(); - String current_label = first(context.cfg.get_by_path("theme/label").to_string(), current_theme); - String route_path = context.var["starter"]["route"]["l_path"].to_string(); - - <> -
- - - -
- - - -} diff --git a/site/info/uce-starter/components/gauges/arcgauge.uce b/site/info/uce-starter/components/gauges/arcgauge.uce deleted file mode 100644 index a9b406a..0000000 --- a/site/info/uce-starter/components/gauges/arcgauge.uce +++ /dev/null @@ -1,91 +0,0 @@ -#load "helpers.uce" - -COMPONENT(Request& context) -{ - starter_register_js("components/gauges/common.js", context); - starter_register_css("themes/common/css/gauges.css", context); - - String gauge_id = first(context.call["id"].to_string(), "arcgauge-" + std::to_string((u64)time())); - String title = context.call["title"].to_string(); - String subtitle = context.call["subtitle"].to_string(); - String style = context.call["style"].to_string(); - DTree scale = context.call["scale"]; - - <> -
- -
-

-

-
- -
- 0.0 ? gauge_clamp_value((value / max_value) * 100.0, 0.0, 100.0) : 0.0; - f64 arc_length = round((pct / 100.0) * 157.08 * 10.0) / 10.0; - String resolved_color = ""; - if(merged["color"].get_type_name() == "array") - resolved_color = gauge_range_color(merged["color"], value); - else - resolved_color = merged["color"].to_string(); - if(resolved_color == "") - { - if(pct >= 85.0) - resolved_color = "var(--error, #ef4444)"; - else if(pct >= 60.0) - resolved_color = "var(--warning, #f59e0b)"; - else - resolved_color = "var(--success, #10b981)"; - } - String display_value = gauge_format_number(value, precision) + merged["unit"].to_string(); - String watermark_prefix = merged["watermark_prefix"].to_string(); - ?>
-
- -
-
-
-
- - - - -} diff --git a/site/info/uce-starter/components/gauges/common.css b/site/info/uce-starter/components/gauges/common.css deleted file mode 100755 index e45daa7..0000000 --- a/site/info/uce-starter/components/gauges/common.css +++ /dev/null @@ -1,95 +0,0 @@ - .horizontal .progressbar-item { - display: flex; - min-width: 100%; - padding: 5px; - } - - .progressbar-container.vertical { - display: flex; - } - - .vertical .progressbar-item { - display: flex; - flex-direction: column; - justify-content: flex-end; - padding: 5px; - text-align: center; - } - - .progressbar-label { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - font-weight: bold; - } - - .horizontal .progressbar-label, .horizontal .progressbar-value { - flex: 0 0 auto; - margin-right: 10px; - } - - .horizontal .progressbar-label { - min-width: 50px; - } - - .vertical .progressbar-label { - text-align: center; - } - - .horizontal .progressbar-value { - min-width: 50px; - text-align: right; - } - - .progressbar-background { - flex: 1; - background: var(--bg-color); - padding: 4px; - display: flex; - } - - .vertical .progressbar-background { - flex-direction: column; - justify-content: flex-end; - } - - .progressbar-bar { - transition: all 0.3s ease; - } - - .progressbar-marker { - position: absolute; - z-index: 10; - opacity: 0.5; - background: var(--text-color, #333); - } - - .progressbar-marker:hover { - opacity: 1; - } - - .horizontal .progressbar-marker { - border-width: 0 2px 0 2px; - height: 100%; - top: 0; - min-width: 4px; - } - - .vertical .progressbar-marker { - border-width: 2px 0 2px 0; - width: 100%; - left: 0; - min-height: 4px; - } - - .progressbar-background { - position: relative; - } - - .needlegauge-svg .needle { - transition: all 0.3s ease; - } - - .needlegauge-item { - display: inline-block; - } \ No newline at end of file diff --git a/site/info/uce-starter/components/gauges/common.js b/site/info/uce-starter/components/gauges/common.js deleted file mode 100755 index 76ab786..0000000 --- a/site/info/uce-starter/components/gauges/common.js +++ /dev/null @@ -1,121 +0,0 @@ -// common code for gauges components - -window.GaugeComponents = window.GaugeComponents || {}; - -Object.assign(window.GaugeComponents, { // as a namespace - - // utility functions - clampValue: function(value, min, max) { - return Math.min(max, Math.max(min, value)); - }, - - pickEntryFromRange: function(ranges, value) { - if (!Array.isArray(ranges)) return null; - for (const entry of ranges) { - if (value >= entry.from && value <= entry.to) return entry; - } - return null; - }, - - /** - * Creates an SVG element with namespace - */ - createSVGElement: function(tagName, attributes = {}) { - const element = document.createElementNS('http://www.w3.org/2000/svg', tagName); - Object.entries(attributes).forEach(([key, value]) => { - element.setAttribute(key, value); - }); - return element; - }, - - /** - * Gets CSS custom property value from computed styles - */ - getCSSVar: function(varName) { - return getComputedStyle(document.documentElement).getPropertyValue(varName).trim(); - }, - - resolveColor: function(colorSpec, value, pct) { - if (Array.isArray(colorSpec)) { - const match = this.pickEntryFromRange(colorSpec, value); - if (match && match.color) return match.color; - } - if (typeof colorSpec === 'string' && colorSpec !== '') return colorSpec; - if (pct < 60) return this.getCSSVar('--success') || '#10b981'; - if (pct < 85) return this.getCSSVar('--warning') || '#f59e0b'; - return this.getCSSVar('--error') || '#ef4444'; - }, - - formatValue: function(value, precision, suffix) { - const numericValue = Number(value); - const normalizedPrecision = Number.isFinite(precision) ? precision : 1; - if (!Number.isFinite(numericValue)) return '--'; - return numericValue.toFixed(normalizedPrecision) + (suffix || ''); - }, - - gaugeArcPoint: function(pct, radius = 50) { - const angle = Math.PI - (pct / 100) * Math.PI; - return { - x: 60 + radius * Math.cos(angle), - y: 60 - radius * Math.sin(angle), - }; - }, - - updateWatermark: function(prefix, pct) { - const now = Date.now(); - this._watermarks = this._watermarks || {}; - let watermark = this._watermarks[prefix]; - const resetWindow = 10 * 60 * 1000; - if (!watermark || (now - watermark.resetTs) > resetWindow) { - watermark = { lo: pct, hi: pct, resetTs: now }; - this._watermarks[prefix] = watermark; - } else { - if (pct < watermark.lo) watermark.lo = pct; - if (pct > watermark.hi) watermark.hi = pct; - } - return watermark; - }, - - renderWatermarkTick: function(lineId, pct) { - const line = document.getElementById(lineId); - if (!line) return; - if (pct == null) { - line.setAttribute('opacity', '0'); - return; - } - const outer = this.gaugeArcPoint(pct, 53); - const inner = this.gaugeArcPoint(pct, 43); - line.setAttribute('x1', outer.x.toFixed(1)); - line.setAttribute('y1', outer.y.toFixed(1)); - line.setAttribute('x2', inner.x.toFixed(1)); - line.setAttribute('y2', inner.y.toFixed(1)); - line.setAttribute('opacity', '0.7'); - }, - - updateArcGauge: function(options) { - const value = Number(options.value); - const max = Number(options.max || 100); - const normalizedValue = Number.isFinite(value) ? value : 0; - const pct = this.clampValue(max === 0 ? 0 : (normalizedValue / max) * 100, 0, 100); - const arcLength = (pct / 100) * 157.08; - const arc = document.getElementById(options.arcId); - const text = document.getElementById(options.textId); - const meta = options.metaId ? document.getElementById(options.metaId) : null; - if (arc) { - arc.setAttribute('stroke-dasharray', arcLength.toFixed(1) + ' 157.08'); - arc.setAttribute('stroke', this.resolveColor(options.color, normalizedValue, pct)); - } - if (text) { - text.textContent = this.formatValue(normalizedValue, options.precision, options.suffix); - } - if (meta && options.meta != null) { - meta.textContent = options.meta; - } - if (options.watermarkPrefix) { - const watermark = this.updateWatermark(options.watermarkPrefix, pct); - this.renderWatermarkTick(options.watermarkPrefix + 'WmLo', watermark.lo); - this.renderWatermarkTick(options.watermarkPrefix + 'WmHi', watermark.hi); - } - } - -}); \ No newline at end of file diff --git a/site/info/uce-starter/components/gauges/helpers.uce b/site/info/uce-starter/components/gauges/helpers.uce deleted file mode 100644 index 5fb6421..0000000 --- a/site/info/uce-starter/components/gauges/helpers.uce +++ /dev/null @@ -1,71 +0,0 @@ -#load "../../lib/app.uce" -#include - -f64 gauge_clamp_value(f64 value, f64 min_value, f64 max_value) -{ - return(std::max(min_value, std::min(max_value, value))); -} - -f64 gauge_pi() -{ - return(3.14159265358979323846); -} - -String gauge_string_attr(String value) -{ - return(html_escape(value)); -} - -String gauge_attr_id(String value) -{ - return(ascii_safe_name(value)); -} - -String gauge_range_color(DTree ranges, f64 value) -{ - String matched = ""; - ranges.each([&](DTree 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 == "") - matched = range["color"].to_string(); - }); - return(matched); -} - -String gauge_arc_path(f64 cx, f64 cy, f64 radius, f64 start_angle, f64 end_angle) -{ - f64 start_x = cx + cos(start_angle) * radius; - f64 start_y = cy + sin(start_angle) * radius; - f64 end_x = cx + cos(end_angle) * radius; - f64 end_y = cy + sin(end_angle) * radius; - s32 large_arc = fabs(end_angle - start_angle) > gauge_pi() ? 1 : 0; - s32 sweep = end_angle >= start_angle ? 1 : 0; - return( - "M " + std::to_string(start_x) + " " + std::to_string(start_y) + - " A " + std::to_string(radius) + " " + std::to_string(radius) + - " 0 " + std::to_string(large_arc) + " " + std::to_string(sweep) + - " " + std::to_string(end_x) + " " + std::to_string(end_y) - ); -} - -String gauge_circle_segment_svg(f64 cx, f64 cy, f64 radius, f64 start_angle, f64 end_angle, String stroke, f64 stroke_width, String fill, String style) -{ - String path_d = gauge_arc_path(cx, cy, radius, start_angle, end_angle); - return( - "" - ); -} - -String gauge_format_number(f64 value, s32 precision) -{ - char buf[64]; - snprintf(buf, sizeof(buf), ("%." + std::to_string(std::max(0, precision)) + "f").c_str(), value); - return(String(buf)); -} diff --git a/site/info/uce-starter/components/gauges/needlegauge.uce b/site/info/uce-starter/components/gauges/needlegauge.uce deleted file mode 100644 index 25ed3f1..0000000 --- a/site/info/uce-starter/components/gauges/needlegauge.uce +++ /dev/null @@ -1,144 +0,0 @@ -#load "helpers.uce" - -COMPONENT(Request& context) -{ - starter_register_js("components/gauges/common.js", context); - starter_register_css("themes/common/css/gauges.css", context); - - String gauge_id = first(context.call["id"].to_string(), "needlegauge-" + std::to_string((u64)time())); - String style = context.call["style"].to_string(); - String title = context.call["title"].to_string(); - String subtitle = context.call["subtitle"].to_string(); - f64 size = float_val(first(context.call["size"].to_string(), "200")); - DTree scale = context.call["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.call["img_height"].to_string(), std::to_string(size * std::max(cos(scale_angle_start), cos(scale_angle_end))))); - - <> -
- -
-

-

-
- -
- "; - } - for(f64 v = min_value; v <= max_value + 0.0001; v += label_interval) - { - f64 angle = angle_start + ((v - min_value) / vrange) * (angle_end - angle_start); - f64 x1 = size / 2.0 + cos(angle) * size * 0.35; - f64 y1 = size / 2.0 + sin(angle) * size * 0.35; - f64 x2 = size / 2.0 + cos(angle) * size * 0.41; - f64 y2 = size / 2.0 + sin(angle) * size * 0.41; - ticks_html += ""; - f64 lx = size / 2.0 + cos(angle) * size * 0.45; - f64 ly = size / 2.0 + sin(angle) * size * 0.45; - String label_value = std::to_string((s64)round(v)); - ticks_html += "" + - html_escape(label_value) + ""; - } - String segments_html = ""; - if(merged["color"].get_type_name() == "array") - { - merged["color"].each([&](DTree 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); - f64 angle_to = angle_start + ((range_to - min_value) / vrange) * (angle_end - angle_start); - segments_html += gauge_circle_segment_svg(size / 2.0, size / 2.0, size * 0.4, angle_from, angle_to, first(range["color"].to_string(), "rgba(120,120,120,0.5)"), 8.0, "rgba(0,0,0,0)", "opacity:0.25"); - }); - } - else - { - segments_html = gauge_circle_segment_svg(size / 2.0, size / 2.0, size * 0.4, angle_start, angle_end, tick_color, 8.0, "rgba(0,0,0,0)", "opacity:0.25"); - } - ?>
-
-
- - - - - - -
-
-
-
-
-
-
-
- - - - -} diff --git a/site/info/uce-starter/components/gauges/progressbar.uce b/site/info/uce-starter/components/gauges/progressbar.uce deleted file mode 100644 index 1410243..0000000 --- a/site/info/uce-starter/components/gauges/progressbar.uce +++ /dev/null @@ -1,168 +0,0 @@ -#load "helpers.uce" - -COMPONENT(Request& context) -{ - starter_register_js("components/gauges/common.js", context); - starter_register_css("themes/common/css/gauges.css", context); - - String gauge_id = first(context.call["id"].to_string(), "progressbar-" + std::to_string((u64)time())); - String style = context.call["style"].to_string(); - String item_style = context.call["item-style"].to_string(); - String label_style = context.call["label-style"].to_string(); - String value_style = context.call["value-style"].to_string(); - String bar_style = context.call["bar-style"].to_string(); - String title = context.call["title"].to_string(); - String subtitle = context.call["subtitle"].to_string(); - String layout = first(context.call["layout"].to_string(), "horizontal"); - String bar_color_default = context.call["bar-color"].to_string(); - DTree scale = context.call["scale"]; - DTree markers = context.call["markers"]; - - StringList default_palette; - default_palette.push_back("var(--success, #10b981)"); - default_palette.push_back("var(--primary, #60a5fa)"); - default_palette.push_back("var(--accent, #22d3ee)"); - default_palette.push_back("var(--warning, #f59e0b)"); - u32 auto_color_counter = 0; - - <> -
- -
-

-

-
- - -
-
- -
-
-
-
-
-
-
" - style="left: %; background: ;">
-
-
- -
-
- -
px;"> -
- -
-
-
-
" - style="bottom: %; background: ;">
-
-
-
- -
-
- -
- - - - -} diff --git a/site/info/uce-starter/components/theme/account_links.uce b/site/info/uce-starter/components/theme/account_links.uce deleted file mode 100644 index 96018c2..0000000 --- a/site/info/uce-starter/components/theme/account_links.uce +++ /dev/null @@ -1,32 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - StarterUser users(context); - DTree 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.call["wrapper_class"].to_string(), theme_key == "localfirst" ? "admin-account-card" : "nav-account nav-menu"); - String links_class = first(context.call["links_wrapper_class"].to_string(), theme_key == "localfirst" ? "admin-account-links" : ""); - String name_class = first(context.call["name_class"].to_string(), theme_key == "localfirst" ? "admin-account-name" : "account-name"); - - <> -
- - - - - - -
- -} diff --git a/site/info/uce-starter/components/theme/footer.uce b/site/info/uce-starter/components/theme/footer.uce deleted file mode 100644 index 1a81513..0000000 --- a/site/info/uce-starter/components/theme/footer.uce +++ /dev/null @@ -1,22 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - if(embed_mode) - return; - - String text = first(context.cfg.get_by_path("theme/footer_text").to_string(), context.cfg.get_by_path("site/name").to_string()); - String inner_class = first(context.call["inner_class"].to_string(), context.cfg.get_by_path("theme/key").to_string() == "portal-light" ? "footer-inner" : ""); - - <> -
- -

- -

- -
- -} diff --git a/site/info/uce-starter/components/theme/global_controls.uce b/site/info/uce-starter/components/theme/global_controls.uce deleted file mode 100644 index 9af2162..0000000 --- a/site/info/uce-starter/components/theme/global_controls.uce +++ /dev/null @@ -1,18 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - if(starter_page_embed_mode(context)) - return; - - String cookie_value = context.call["cookie_consent"].to_string(); - bool cookie_consent = !(cookie_value == "0" || cookie_value == "false" || cookie_value == "FALSE" || cookie_value == "no" || cookie_value == "NO"); - - <> - - - - - -} diff --git a/site/info/uce-starter/components/theme/head.uce b/site/info/uce-starter/components/theme/head.uce deleted file mode 100644 index 77ddaa7..0000000 --- a/site/info/uce-starter/components/theme/head.uce +++ /dev/null @@ -1,22 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - String title = first(context.var["starter"]["page_title"].to_string(), context.cfg.get_by_path("site/default_page_title").to_string()); - String description = first(context.cfg.get_by_path("theme/meta_description").to_string(), "UCE starter example"); - String theme_color = first(context.cfg.get_by_path("theme/theme_color").to_string(), "#0f172a"); - String icon = starter_asset_url(context.cfg.get_by_path("theme/path").to_string() + "icon.png", context); - - <> - - <?= title + " | " + context.cfg.get_by_path("site/name").to_string() ?> - - - - - - - - -} diff --git a/site/info/uce-starter/components/theme/page_shell.uce b/site/info/uce-starter/components/theme/page_shell.uce deleted file mode 100644 index 890f2c2..0000000 --- a/site/info/uce-starter/components/theme/page_shell.uce +++ /dev/null @@ -1,20 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - if(context.call["main_html"].to_string() != "") - context.var["starter"]["fragments"]["main"] = context.call["main_html"]; - if(context.call["json"].get_type_name() == "array") - context.var["starter"]["json"] = context.call["json"]; - if(context.call["page_type"].to_string() != "") - context.var["starter"]["page_type"] = context.call["page_type"]; - if(context.call["embed_mode"].to_string() != "") - context.var["starter"]["embed_mode"] = context.call["embed_mode"]; - starter_render_page(context); -} - -COMPONENT:HEAD(Request& context) -{ - print(component("head", context.call, context)); -} diff --git a/site/info/uce-starter/components/theme/standard_nav.uce b/site/info/uce-starter/components/theme/standard_nav.uce deleted file mode 100644 index 587548a..0000000 --- a/site/info/uce-starter/components/theme/standard_nav.uce +++ /dev/null @@ -1,31 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - String nav_class = context.call["nav_class"].to_string(); - 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; - if(context.call["account_wrapper_class"].to_string() != "") - account_props["wrapper_class"] = context.call["account_wrapper_class"]; - if(context.call["links_wrapper_class"].to_string() != "") - account_props["links_wrapper_class"] = context.call["links_wrapper_class"]; - if(context.call["name_class"].to_string() != "") - account_props["name_class"] = context.call["name_class"]; - - <> - > - - - - -} diff --git a/site/info/uce-starter/components/workspace/primitives.uce b/site/info/uce-starter/components/workspace/primitives.uce deleted file mode 100644 index f63a2c3..0000000 --- a/site/info/uce-starter/components/workspace/primitives.uce +++ /dev/null @@ -1,122 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT:APP_FRAME(Request& context) -{ - starter_register_css("themes/common/css/workspace.css", context); - starter_register_js("js/u-workspace-shell.js", context); - String id = context.call["id"].to_string(); - String overlay_id = context.call["overlay_id"].to_string(); - String class_name = context.call["class"].to_string(); - <> - class="ws-app"> - - class="ws-sidebar-overlay">
-
- - -} - -COMPONENT:EMPTY_STATE(Request& context) -{ - <> -
"> -
">
-

-

- -
- -} - -COMPONENT:LIST_STATE(Request& context) -{ - <> -
">">
- -} - -COMPONENT:MOBILE_BAR(Request& context) -{ - <> -
"> - class="ws-mobile-toggle" title="Toggle sidebar" type="button"> - "> - - -
- -} - -COMPONENT:PANEL_HEADER(Request& context) -{ - <> -
"> -
-

-

-
-
-
- -} - -COMPONENT:PANEL(Request& context) -{ - <> - class="ws-panel"> - - - - -} - -COMPONENT:SECTION_HEAD(Request& context) -{ - <> -
"> -

-
-
- -} - -COMPONENT:SECTION(Request& context) -{ - <> - class="ws-section"> - - - - -} - -COMPONENT:SIDEBAR_SHELL(Request& context) -{ - <> - class="ws-sidebar"> - - - - -} - -COMPONENT:SIDEBAR_TOOLBAR(Request& context) -{ - <> -
"> - -
- - name="" class="ws-search-input" placeholder="" autocomplete="off"> -
-
- -} - -COMPONENT:STATUS_PILL(Request& context) -{ - String variant = to_lower(first(context.call["variant"].to_string(), "neutral")); - <> - "> - -} diff --git a/site/info/uce-starter/config/settings.uce b/site/info/uce-starter/config/settings.uce deleted file mode 100644 index ce371f6..0000000 --- a/site/info/uce-starter/config/settings.uce +++ /dev/null @@ -1,73 +0,0 @@ -DTree get_config() -{ - DTree config; - - config["site"]["name"] = "UCE Starter"; - config["site"]["default_page_title"] = "Home"; - config["site"]["timezone"] = "UTC"; - - config["users"]["enable_signup"].set_bool(true); - config["filebase"]["path"] = "/tmp/uce-starter-data"; - - config["theme"]["key"] = "portal-dark"; - config["theme"]["options"]["light"]["label"] = "Starter Light"; - config["theme"]["options"]["light"]["path"] = "themes/light/"; - config["theme"]["options"]["light"]["mode"] = "light"; - config["theme"]["options"]["light"]["description"] = "Original starter light theme kept for backward compatibility."; - config["theme"]["options"]["light"]["footer_text"] = "UCE Starter running with the Starter Light theme."; - config["theme"]["options"]["light"]["meta_description"] = "Starter Light theme for the UCE starter"; - config["theme"]["options"]["light"]["theme_color"] = "#3b82f6"; - - config["theme"]["options"]["dark"]["label"] = "Starter Dark"; - config["theme"]["options"]["dark"]["path"] = "themes/dark/"; - config["theme"]["options"]["dark"]["mode"] = "dark"; - config["theme"]["options"]["dark"]["description"] = "Original starter dark theme kept for backward compatibility."; - config["theme"]["options"]["dark"]["footer_text"] = "UCE Starter running with the Starter Dark theme."; - config["theme"]["options"]["dark"]["meta_description"] = "Starter Dark theme for the UCE starter"; - config["theme"]["options"]["dark"]["theme_color"] = "#0f172a"; - - config["theme"]["options"]["portal-light"]["label"] = "AI Portal Light"; - config["theme"]["options"]["portal-light"]["path"] = "themes/portal-light/"; - config["theme"]["options"]["portal-light"]["mode"] = "light"; - config["theme"]["options"]["portal-light"]["description"] = "Dense, corporate portal layout in a light palette."; - config["theme"]["options"]["portal-light"]["footer_text"] = "UCE Starter running with the AI Portal Light starter theme."; - config["theme"]["options"]["portal-light"]["meta_description"] = "AI Portal Light theme for the UCE starter"; - config["theme"]["options"]["portal-light"]["theme_color"] = "#0f68ad"; - - config["theme"]["options"]["portal-dark"]["label"] = "AI Portal Dark"; - config["theme"]["options"]["portal-dark"]["path"] = "themes/portal-dark/"; - config["theme"]["options"]["portal-dark"]["mode"] = "dark"; - config["theme"]["options"]["portal-dark"]["description"] = "Glassy dark portal shell and the current default starter theme."; - config["theme"]["options"]["portal-dark"]["footer_text"] = "UCE Starter running with the AI Portal Dark starter theme."; - config["theme"]["options"]["portal-dark"]["meta_description"] = "AI Portal Dark theme for the UCE starter"; - config["theme"]["options"]["portal-dark"]["theme_color"] = "#0f172a"; - - config["theme"]["options"]["localfirst"]["label"] = "Local First"; - config["theme"]["options"]["localfirst"]["path"] = "themes/localfirst/"; - config["theme"]["options"]["localfirst"]["mode"] = "dark"; - config["theme"]["options"]["localfirst"]["description"] = "llm2-derived admin shell with sidebar chrome."; - config["theme"]["options"]["localfirst"]["footer_text"] = "UCE Starter running with the Local First starter theme."; - config["theme"]["options"]["localfirst"]["meta_description"] = "Local First admin-shell theme for the UCE starter"; - config["theme"]["options"]["localfirst"]["theme_color"] = "#020913"; - - config["theme"]["options"]["retro-gaming"]["label"] = "Retro Gaming"; - config["theme"]["options"]["retro-gaming"]["path"] = "themes/retro-gaming/"; - config["theme"]["options"]["retro-gaming"]["mode"] = "dark"; - config["theme"]["options"]["retro-gaming"]["description"] = "CRT scanlines, pixel font, neon glow."; - config["theme"]["options"]["retro-gaming"]["footer_text"] = "INSERT COIN // UCE Starter running the Retro Gaming theme."; - config["theme"]["options"]["retro-gaming"]["meta_description"] = "Retro Gaming pixel theme for the UCE starter"; - config["theme"]["options"]["retro-gaming"]["theme_color"] = "#0a0a1a"; - - config["menu"][""]["title"] = "Home"; - config["menu"][""]["hidden"].set_bool(true); - config["menu"]["page1"]["title"] = "Components"; - config["menu"]["features"]["title"] = "Features"; - config["menu"]["page2"]["title"] = "Ajaxy"; - config["menu"]["gauges"]["title"] = "Gauges"; - config["menu"]["dashboard"]["title"] = "Dashboard"; - config["menu"]["workspace"]["title"] = "Workspace"; - config["menu"]["themes"]["title"] = "Themes"; - config["menu"]["auth/demo"]["title"] = "Auth"; - - return(config); -} \ No newline at end of file diff --git a/site/info/uce-starter/img/cat01.jpg b/site/info/uce-starter/img/cat01.jpg deleted file mode 100755 index 39c227a..0000000 Binary files a/site/info/uce-starter/img/cat01.jpg and /dev/null differ diff --git a/site/info/uce-starter/img/cat02.jpg b/site/info/uce-starter/img/cat02.jpg deleted file mode 100755 index 39c227a..0000000 Binary files a/site/info/uce-starter/img/cat02.jpg and /dev/null differ diff --git a/site/info/uce-starter/img/cat03.jpg b/site/info/uce-starter/img/cat03.jpg deleted file mode 100755 index 39c227a..0000000 Binary files a/site/info/uce-starter/img/cat03.jpg and /dev/null differ diff --git a/site/info/uce-starter/img/cat04.jpg b/site/info/uce-starter/img/cat04.jpg deleted file mode 100755 index 39c227a..0000000 Binary files a/site/info/uce-starter/img/cat04.jpg and /dev/null differ diff --git a/site/info/uce-starter/img/cat05.jpg b/site/info/uce-starter/img/cat05.jpg deleted file mode 100755 index 39c227a..0000000 Binary files a/site/info/uce-starter/img/cat05.jpg and /dev/null differ diff --git a/site/info/uce-starter/img/cat06.jpg b/site/info/uce-starter/img/cat06.jpg deleted file mode 100755 index 39c227a..0000000 Binary files a/site/info/uce-starter/img/cat06.jpg and /dev/null differ diff --git a/site/info/uce-starter/index.uce b/site/info/uce-starter/index.uce deleted file mode 100644 index 6c5513f..0000000 --- a/site/info/uce-starter/index.uce +++ /dev/null @@ -1,29 +0,0 @@ -#load "lib/app.uce" - -RENDER(Request& context) -{ - app_init(context); - - DTree resolved = app_resolve_view(context); - - ob_start(); - if(resolved["file"].to_string() != "") - { - if(resolved["param"].to_string() != "") - context.var["app"]["route"]["param"] = resolved["param"]; - unit_render(resolved["file"].to_string(), context); - } - else - { - app_not_found("The requested page does not exist.", context); - <> -
-

404 Not Found

-

-
- - } - String main_html = ob_get_close(); - context.var["app"]["fragments"]["main"] = main_html; - app_render_page(context); -} diff --git a/site/info/uce-starter/js/ag-grid/ag-grid-community.min.js b/site/info/uce-starter/js/ag-grid/ag-grid-community.min.js deleted file mode 100755 index 1a78246..0000000 --- a/site/info/uce-starter/js/ag-grid/ag-grid-community.min.js +++ /dev/null @@ -1,8 +0,0 @@ -/** - * @ag-grid-community/all-modules - Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue - * @version v31.1.0 - * @link https://www.ag-grid.com/ - * @license MIT - */ -// @ag-grid-community/all-modules v31.1.0 -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.agGrid=t():e.agGrid=t()}(window,(function(){return function(e){var t={};function a(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,a),o.l=!0,o.exports}return a.m=e,a.c=t,a.d=function(e,t,r){a.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,t){if(1&t&&(e=a(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(a.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)a.d(r,o,function(t){return e[t]}.bind(null,o));return r},a.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(t,"a",t),t},a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},a.p="",a(a.s=6)}([function(e,t,a){"use strict";a.r(t),a.d(t,"ColumnFactory",(function(){return it})),a.d(t,"ColumnModel",(function(){return kt})),a.d(t,"ColumnKeyCreator",(function(){return M})),a.d(t,"ColumnUtils",(function(){return At})),a.d(t,"DisplayedGroupCreator",(function(){return Ot})),a.d(t,"GroupInstanceIdCreator",(function(){return gt})),a.d(t,"GROUP_AUTO_COLUMN_ID",(function(){return ct})),a.d(t,"ComponentUtil",(function(){return Nt})),a.d(t,"AgStackComponentsRegistry",(function(){return Ut})),a.d(t,"UserComponentRegistry",(function(){return un})),a.d(t,"UserComponentFactory",(function(){return Pn})),a.d(t,"ColDefUtil",(function(){return Ln})),a.d(t,"BeanStub",(function(){return at})),a.d(t,"Context",(function(){return ie})),a.d(t,"Autowired",(function(){return de})),a.d(t,"PostConstruct",(function(){return le})),a.d(t,"PreConstruct",(function(){return ne})),a.d(t,"Optional",(function(){return ce})),a.d(t,"Bean",(function(){return ge})),a.d(t,"Qualifier",(function(){return pe})),a.d(t,"PreDestroy",(function(){return se})),a.d(t,"QuerySelector",(function(){return po})),a.d(t,"RefSelector",(function(){return ho})),a.d(t,"ExcelFactoryMode",(function(){return Nn})),a.d(t,"DragAndDropService",(function(){return Ii})),a.d(t,"DragSourceType",(function(){return Ni})),a.d(t,"DragService",(function(){return In})),a.d(t,"VirtualListDragFeature",(function(){return _n})),a.d(t,"Column",(function(){return Ee})),a.d(t,"ColumnGroup",(function(){return lt})),a.d(t,"ProvidedColumnGroup",(function(){return xe})),a.d(t,"RowNode",(function(){return Ai})),a.d(t,"RowHighlightPosition",(function(){return Bn})),a.d(t,"FilterManager",(function(){return Jn})),a.d(t,"ProvidedFilter",(function(){return ko})),a.d(t,"SimpleFilter",(function(){return Ho})),a.d(t,"ScalarFilter",(function(){return _o})),a.d(t,"NumberFilter",(function(){return ei})),a.d(t,"TextFilter",(function(){return ai})),a.d(t,"DateFilter",(function(){return Wo})),a.d(t,"TextFloatingFilter",(function(){return si})),a.d(t,"HeaderFilterCellComp",(function(){return $n})),a.d(t,"FloatingFilterMapper",(function(){return On})),a.d(t,"GridBodyComp",(function(){return $l})),a.d(t,"GridBodyCtrl",(function(){return cl})),a.d(t,"RowAnimationCssClasses",(function(){return gl})),a.d(t,"ScrollVisibleService",(function(){return ts})),a.d(t,"MouseEventService",(function(){return os})),a.d(t,"NavigationService",(function(){return ns})),a.d(t,"RowContainerComp",(function(){return us})),a.d(t,"RowContainerName",(function(){return Wl})),a.d(t,"RowContainerCtrl",(function(){return Jl})),a.d(t,"RowContainerType",(function(){return Ul})),a.d(t,"getRowContainerTypeForName",(function(){return Kl})),a.d(t,"BodyDropPivotTarget",(function(){return hs})),a.d(t,"BodyDropTarget",(function(){return bs})),a.d(t,"CssClassApplier",(function(){return Rl})),a.d(t,"HeaderRowContainerComp",(function(){return Xs})),a.d(t,"GridHeaderComp",(function(){return og})),a.d(t,"GridHeaderCtrl",(function(){return ag})),a.d(t,"HeaderRowComp",(function(){return ks})),a.d(t,"HeaderRowType",(function(){return Rs})),a.d(t,"HeaderRowCtrl",(function(){return Ks})),a.d(t,"HeaderCellCtrl",(function(){return Vs})),a.d(t,"SortIndicatorComp",(function(){return ci})),a.d(t,"HeaderFilterCellCtrl",(function(){return Ls})),a.d(t,"HeaderGroupCellCtrl",(function(){return Ws})),a.d(t,"AbstractHeaderCellCtrl",(function(){return As})),a.d(t,"HeaderRowContainerCtrl",(function(){return Qs})),a.d(t,"HorizontalResizeService",(function(){return ng})),a.d(t,"MoveColumnFeature",(function(){return fs})),a.d(t,"StandardMenuFactory",(function(){return sg})),a.d(t,"TabbedLayout",(function(){return hg})),a.d(t,"ResizeObserverService",(function(){return vg})),a.d(t,"AnimationFrameService",(function(){return wg})),a.d(t,"ExpansionService",(function(){return yg})),a.d(t,"MenuService",(function(){return Eg})),a.d(t,"LargeTextCellEditor",(function(){return wi})),a.d(t,"PopupEditorWrapper",(function(){return ss})),a.d(t,"SelectCellEditor",(function(){return Ci})),a.d(t,"TextCellEditor",(function(){return Ri})),a.d(t,"NumberCellEditor",(function(){return $i})),a.d(t,"DateCellEditor",(function(){return tn})),a.d(t,"DateStringCellEditor",(function(){return on})),a.d(t,"CheckboxCellEditor",(function(){return gn})),a.d(t,"Beans",(function(){return bl})),a.d(t,"AnimateShowChangeCellRenderer",(function(){return ki})),a.d(t,"AnimateSlideCellRenderer",(function(){return Ti})),a.d(t,"GroupCellRenderer",(function(){return ji})),a.d(t,"GroupCellRendererCtrl",(function(){return Wi})),a.d(t,"SetLeftFeature",(function(){return Os})),a.d(t,"PositionableFeature",(function(){return Ro})),a.d(t,"AutoWidthCalculator",(function(){return xg})),a.d(t,"CheckboxSelectionComponent",(function(){return Pi})),a.d(t,"CellComp",(function(){return gs})),a.d(t,"CellCtrl",(function(){return kl})),a.d(t,"RowCtrl",(function(){return Al})),a.d(t,"RowRenderer",(function(){return Ag})),a.d(t,"ValueFormatterService",(function(){return Mg})),a.d(t,"CssClassManager",(function(){return so})),a.d(t,"CheckboxCellRenderer",(function(){return ln})),a.d(t,"PinnedRowModel",(function(){return Lg})),a.d(t,"ServerSideTransactionResultStatus",(function(){return Ng})),a.d(t,"ChangedPath",(function(){return Fg})),a.d(t,"RowNodeBlock",(function(){return Ig})),a.d(t,"RowNodeBlockLoader",(function(){return _g})),a.d(t,"PaginationProxy",(function(){return qg})),a.d(t,"ClientSideRowModelSteps",(function(){return bg})),a.d(t,"StylingService",(function(){return Ug})),a.d(t,"LayoutCssClasses",(function(){return el})),a.d(t,"AgAbstractField",(function(){return Ao})),a.d(t,"AgCheckbox",(function(){return Io})),a.d(t,"AgRadioButton",(function(){return Go})),a.d(t,"AgToggleButton",(function(){return jg})),a.d(t,"AgInputTextField",(function(){return Jo})),a.d(t,"AgInputTextArea",(function(){return Kg})),a.d(t,"AgInputNumberField",(function(){return Xo})),a.d(t,"AgInputDateField",(function(){return Yg})),a.d(t,"AgInputRange",(function(){return Qg})),a.d(t,"AgRichSelect",(function(){return td})),a.d(t,"AgSelect",(function(){return Lo})),a.d(t,"AgSlider",(function(){return rd})),a.d(t,"AgGroupComponent",(function(){return id})),a.d(t,"AgMenuItemRenderer",(function(){return dn})),a.d(t,"AgMenuItemComponent",(function(){return cd})),a.d(t,"AgMenuList",(function(){return ld})),a.d(t,"AgMenuPanel",(function(){return gd})),a.d(t,"AgDialog",(function(){return md})),a.d(t,"AgPanel",(function(){return pd})),a.d(t,"Component",(function(){return uo})),a.d(t,"ManagedFocusFeature",(function(){return So})),a.d(t,"TabGuardComp",(function(){return ug})),a.d(t,"TabGuardCtrl",(function(){return cg})),a.d(t,"TabGuardClassNames",(function(){return gg})),a.d(t,"PopupComponent",(function(){return vi})),a.d(t,"PopupService",(function(){return Cd})),a.d(t,"TouchListener",(function(){return gi})),a.d(t,"VirtualList",(function(){return $g})),a.d(t,"AgAbstractLabel",(function(){return To})),a.d(t,"AgPickerField",(function(){return Oo})),a.d(t,"AgAutocomplete",(function(){return xd})),a.d(t,"CellRangeType",(function(){return pl})),a.d(t,"SelectionHandleType",(function(){return ul})),a.d(t,"AutoScrollService",(function(){return Gn})),a.d(t,"VanillaFrameworkOverrides",(function(){return zd})),a.d(t,"CellNavigationService",(function(){return Ad})),a.d(t,"AlignedGridsService",(function(){return Md})),a.d(t,"KeyCode",(function(){return Wr})),a.d(t,"VerticalDirection",(function(){return Di})),a.d(t,"HorizontalDirection",(function(){return Oi})),a.d(t,"Grid",(function(){return _u})),a.d(t,"GridCoreCreator",(function(){return qu})),a.d(t,"createGrid",(function(){return Hu})),a.d(t,"GridApi",(function(){return Un})),a.d(t,"Events",(function(){return st})),a.d(t,"FocusService",(function(){return rc})),a.d(t,"GridOptionsService",(function(){return mu})),a.d(t,"EventService",(function(){return fe})),a.d(t,"SelectableService",(function(){return kc})),a.d(t,"RowNodeSorter",(function(){return Kc})),a.d(t,"CtrlsService",(function(){return Jc})),a.d(t,"GridComp",(function(){return Xd})),a.d(t,"GridCtrl",(function(){return Qd})),a.d(t,"Logger",(function(){return Kd})),a.d(t,"LoggerFactory",(function(){return jd})),a.d(t,"SortController",(function(){return ec})),a.d(t,"TemplateService",(function(){return qd})),a.d(t,"LocaleService",(function(){return fu})),a.d(t,"_",(function(){return $r})),a.d(t,"NumberSequence",(function(){return eo})),a.d(t,"AgPromiseStatus",(function(){return to})),a.d(t,"AgPromise",(function(){return ao})),a.d(t,"Timer",(function(){return ro})),a.d(t,"ValueService",(function(){return Gd})),a.d(t,"ValueCache",(function(){return cc})),a.d(t,"ExpressionService",(function(){return _d})),a.d(t,"ValueParserService",(function(){return xu})),a.d(t,"CellPositionUtils",(function(){return Lc})),a.d(t,"RowPositionUtils",(function(){return Mc})),a.d(t,"HeaderPositionUtils",(function(){return _c})),a.d(t,"HeaderNavigationService",(function(){return eg})),a.d(t,"HeaderNavigationDirection",(function(){return Zs})),a.d(t,"DataTypeService",(function(){return Eu})),a.d(t,"PropertyKeys",(function(){return Pt})),a.d(t,"ColumnApi",(function(){return Fd})),a.d(t,"BaseComponentWrapper",(function(){return Wu})),a.d(t,"Environment",(function(){return yc})),a.d(t,"TooltipFeature",(function(){return fl})),a.d(t,"CustomTooltipFeature",(function(){return lo})),a.d(t,"DEFAULT_CHART_GROUPS",(function(){return Uu})),a.d(t,"CHART_TOOL_PANEL_ALLOW_LIST",(function(){return ju})),a.d(t,"CHART_TOOLBAR_ALLOW_LIST",(function(){return Ku})),a.d(t,"CHART_TOOL_PANEL_MENU_OPTIONS",(function(){return Yu})),a.d(t,"__FORCE_MODULE_DETECTION",(function(){return Qu})),a.d(t,"BarColumnLabelPlacement",(function(){return Ju})),a.d(t,"ModuleNames",(function(){return re})),a.d(t,"ModuleRegistry",(function(){return oe}));var r={};a.r(r),a.d(r,"makeNull",(function(){return y})),a.d(r,"exists",(function(){return S})),a.d(r,"missing",(function(){return E})),a.d(r,"missingOrEmpty",(function(){return R})),a.d(r,"toStringOrNull",(function(){return x})),a.d(r,"attrToNumber",(function(){return k})),a.d(r,"attrToBoolean",(function(){return z})),a.d(r,"attrToString",(function(){return T})),a.d(r,"jsonEquals",(function(){return A})),a.d(r,"defaultComparator",(function(){return D})),a.d(r,"values",(function(){return O}));var o={};a.r(o),a.d(o,"iterateObject",(function(){return P})),a.d(o,"cloneObject",(function(){return L})),a.d(o,"deepCloneDefinition",(function(){return N})),a.d(o,"getAllValuesInObject",(function(){return F})),a.d(o,"mergeDeep",(function(){return I})),a.d(o,"getValueUsingField",(function(){return G})),a.d(o,"removeAllReferences",(function(){return V})),a.d(o,"isNonNullObject",(function(){return H}));var i={};a.r(i),a.d(i,"doOnce",(function(){return B})),a.d(i,"warnOnce",(function(){return q})),a.d(i,"errorOnce",(function(){return W})),a.d(i,"getFunctionName",(function(){return U})),a.d(i,"isFunction",(function(){return j})),a.d(i,"executeInAWhile",(function(){return K})),a.d(i,"executeNextVMTurn",(function(){return J})),a.d(i,"executeAfter",(function(){return X})),a.d(i,"debounce",(function(){return Z})),a.d(i,"throttle",(function(){return $})),a.d(i,"waitUntil",(function(){return ee})),a.d(i,"compose",(function(){return te})),a.d(i,"noop",(function(){return ae}));var n={};a.r(n),a.d(n,"existsAndNotEmpty",(function(){return ze})),a.d(n,"last",(function(){return Te})),a.d(n,"areEqual",(function(){return Ae})),a.d(n,"shallowCompare",(function(){return De})),a.d(n,"sortNumerically",(function(){return Oe})),a.d(n,"removeRepeatsFromArray",(function(){return Me})),a.d(n,"removeFromUnorderedArray",(function(){return Pe})),a.d(n,"removeFromArray",(function(){return Le})),a.d(n,"removeAllFromUnorderedArray",(function(){return Ne})),a.d(n,"removeAllFromArray",(function(){return Fe})),a.d(n,"insertIntoArray",(function(){return Ie})),a.d(n,"insertArrayIntoArray",(function(){return Ge})),a.d(n,"moveInArray",(function(){return Ve})),a.d(n,"includes",(function(){return He})),a.d(n,"flatten",(function(){return _e})),a.d(n,"pushAll",(function(){return Be})),a.d(n,"toStrings",(function(){return qe})),a.d(n,"forEachReverse",(function(){return We}));var l={};a.r(l),a.d(l,"stopPropagationForAgGrid",(function(){return Ke})),a.d(l,"isStopPropagationForAgGrid",(function(){return Ye})),a.d(l,"isEventSupported",(function(){return Qe})),a.d(l,"getCtrlForEventTarget",(function(){return Je})),a.d(l,"isElementInEventPath",(function(){return Xe})),a.d(l,"createEventPath",(function(){return Ze})),a.d(l,"getEventPath",(function(){return $e})),a.d(l,"addSafePassiveEventListener",(function(){return et}));var s={};a.r(s),a.d(s,"utf8_encode",(function(){return mt})),a.d(s,"capitalise",(function(){return vt})),a.d(s,"escapeString",(function(){return ft})),a.d(s,"camelCaseToHumanText",(function(){return wt})),a.d(s,"camelCaseToHyphenated",(function(){return bt}));var g={};a.r(g),a.d(g,"convertToMap",(function(){return Ct})),a.d(g,"mapById",(function(){return yt})),a.d(g,"keys",(function(){return St}));var d={};a.r(d),a.d(d,"setAriaRole",(function(){return Jt})),a.d(d,"getAriaSortState",(function(){return Xt})),a.d(d,"getAriaLevel",(function(){return Zt})),a.d(d,"getAriaPosInSet",(function(){return $t})),a.d(d,"getAriaLabel",(function(){return ea})),a.d(d,"setAriaLabel",(function(){return ta})),a.d(d,"setAriaLabelledBy",(function(){return aa})),a.d(d,"setAriaDescribedBy",(function(){return ra})),a.d(d,"setAriaLive",(function(){return oa})),a.d(d,"setAriaAtomic",(function(){return ia})),a.d(d,"setAriaRelevant",(function(){return na})),a.d(d,"setAriaLevel",(function(){return la})),a.d(d,"setAriaDisabled",(function(){return sa})),a.d(d,"setAriaHidden",(function(){return ga})),a.d(d,"setAriaActiveDescendant",(function(){return da})),a.d(d,"setAriaExpanded",(function(){return ca})),a.d(d,"removeAriaExpanded",(function(){return ua})),a.d(d,"setAriaSetSize",(function(){return pa})),a.d(d,"setAriaPosInSet",(function(){return ha})),a.d(d,"setAriaMultiSelectable",(function(){return ma})),a.d(d,"setAriaRowCount",(function(){return va})),a.d(d,"setAriaRowIndex",(function(){return fa})),a.d(d,"setAriaColCount",(function(){return wa})),a.d(d,"setAriaColIndex",(function(){return ba})),a.d(d,"setAriaColSpan",(function(){return Ca})),a.d(d,"setAriaSort",(function(){return ya})),a.d(d,"removeAriaSort",(function(){return Sa})),a.d(d,"setAriaSelected",(function(){return Ea})),a.d(d,"setAriaChecked",(function(){return Ra})),a.d(d,"setAriaControls",(function(){return xa})),a.d(d,"getAriaCheckboxStateName",(function(){return ka}));var c={};a.r(c),a.d(c,"isBrowserSafari",(function(){return za})),a.d(c,"getSafariVersion",(function(){return Ta})),a.d(c,"isBrowserChrome",(function(){return Aa})),a.d(c,"isBrowserFirefox",(function(){return Da})),a.d(c,"isMacOsUserAgent",(function(){return Oa})),a.d(c,"isIOSUserAgent",(function(){return Ma})),a.d(c,"browserSupportsPreventScroll",(function(){return Pa})),a.d(c,"getTabIndex",(function(){return La})),a.d(c,"getMaxDivHeight",(function(){return Na})),a.d(c,"getBodyWidth",(function(){return Fa})),a.d(c,"getBodyHeight",(function(){return Ia})),a.d(c,"getScrollbarWidth",(function(){return Ga})),a.d(c,"isInvisibleScrollbar",(function(){return Ha}));var u={};a.r(u),a.d(u,"padStartWidthZeros",(function(){return _a})),a.d(u,"createArrayOfNumbers",(function(){return Ba})),a.d(u,"cleanNumber",(function(){return qa})),a.d(u,"decToHex",(function(){return Wa})),a.d(u,"formatNumberTwoDecimalPlacesAndCommas",(function(){return Ua})),a.d(u,"formatNumberCommas",(function(){return ja})),a.d(u,"sum",(function(){return Ka}));var p={};a.r(p),a.d(p,"serialiseDate",(function(){return Ya})),a.d(p,"dateToFormattedString",(function(){return Ja})),a.d(p,"parseDateTimeFromString",(function(){return Xa}));var h={};a.r(h),a.d(h,"radioCssClass",(function(){return $a})),a.d(h,"FOCUSABLE_SELECTOR",(function(){return er})),a.d(h,"FOCUSABLE_EXCLUDE",(function(){return tr})),a.d(h,"isFocusableFormField",(function(){return ar})),a.d(h,"setDisplayed",(function(){return rr})),a.d(h,"setVisible",(function(){return or})),a.d(h,"setDisabled",(function(){return ir})),a.d(h,"isElementChildOfClass",(function(){return nr})),a.d(h,"getElementSize",(function(){return lr})),a.d(h,"getInnerHeight",(function(){return sr})),a.d(h,"getInnerWidth",(function(){return gr})),a.d(h,"getAbsoluteHeight",(function(){return dr})),a.d(h,"getAbsoluteWidth",(function(){return cr})),a.d(h,"getElementRectWithOffset",(function(){return ur})),a.d(h,"isRtlNegativeScroll",(function(){return pr})),a.d(h,"getScrollLeft",(function(){return hr})),a.d(h,"setScrollLeft",(function(){return mr})),a.d(h,"clearElement",(function(){return vr})),a.d(h,"removeFromParent",(function(){return fr})),a.d(h,"isInDOM",(function(){return wr})),a.d(h,"isVisible",(function(){return br})),a.d(h,"loadTemplate",(function(){return Cr})),a.d(h,"ensureDomOrder",(function(){return yr})),a.d(h,"setDomChildOrder",(function(){return Sr})),a.d(h,"insertWithDomOrder",(function(){return Er})),a.d(h,"addStylesToElement",(function(){return Rr})),a.d(h,"isHorizontalScrollShowing",(function(){return xr})),a.d(h,"isVerticalScrollShowing",(function(){return kr})),a.d(h,"setElementWidth",(function(){return zr})),a.d(h,"setFixedWidth",(function(){return Tr})),a.d(h,"setElementHeight",(function(){return Ar})),a.d(h,"setFixedHeight",(function(){return Dr})),a.d(h,"formatSize",(function(){return Or})),a.d(h,"isNodeOrElement",(function(){return Mr})),a.d(h,"copyNodeList",(function(){return Pr})),a.d(h,"iterateNamedNodeMap",(function(){return Lr})),a.d(h,"addOrRemoveAttribute",(function(){return Nr})),a.d(h,"nodeListForEach",(function(){return Fr})),a.d(h,"bindCellRendererToHtmlElement",(function(){return Ir}));var m={};a.r(m),a.d(m,"fuzzyCheckStrings",(function(){return Gr})),a.d(m,"fuzzySuggestions",(function(){return Vr}));var v={};a.r(v),a.d(v,"iconNameClassMap",(function(){return _r})),a.d(v,"createIcon",(function(){return Br})),a.d(v,"createIconNoSpan",(function(){return qr}));var f={};a.r(f),a.d(f,"isEventFromPrintableCharacter",(function(){return Ur})),a.d(f,"isUserSuppressingKeyboardEvent",(function(){return jr})),a.d(f,"isUserSuppressingHeaderKeyboardEvent",(function(){return Kr})),a.d(f,"normaliseQwertyAzerty",(function(){return Yr})),a.d(f,"isDeleteKey",(function(){return Qr}));var w={};a.r(w),a.d(w,"areEventsNear",(function(){return Jr}));var b={};a.r(b),a.d(b,"sortRowNodesByOrder",(function(){return Xr}));var C={};function y(e){return null==e||""===e?null:e}function S(e,t=!1){return null!=e&&(""!==e||t)}function E(e){return!S(e)}function R(e){return null==e||0===e.length}function x(e){return null!=e&&"function"==typeof e.toString?e.toString():null}function k(e){if(void 0===e)return;if(null===e||""===e)return null;if("number"==typeof e)return isNaN(e)?void 0:e;const t=parseInt(e,10);return isNaN(t)?void 0:t}function z(e){if(void 0!==e)return null!==e&&""!==e&&("boolean"==typeof e?e:/true/i.test(e))}function T(e){if(null!=e&&""!==e)return e}function A(e,t){return(e?JSON.stringify(e):null)===(t?JSON.stringify(t):null)}function D(e,t,a=!1){const r=null==e,o=null==t;if(e&&e.toNumber&&(e=e.toNumber()),t&&t.toNumber&&(t=t.toNumber()),r&&o)return 0;if(r)return-1;if(o)return 1;function i(e,t){return e>t?1:et.push(e)),t}return Object.values(e)}a.r(C),a.d(C,"convertToSet",(function(){return Zr}));class M{constructor(){this.existingKeys={}}addExistingKeys(e){for(let t=0;t{if(t&&t.indexOf(e)>=0)return;const o=a[e],i=H(o)&&o.constructor===Object;r[e]=i?N(o):o}),r}function F(e){if(!e)return[];const t=Object;if("function"==typeof t.values)return t.values(e);const a=[];for(const t in e)e.hasOwnProperty(t)&&e.propertyIsEnumerable(t)&&a.push(e[t]);return a}function I(e,t,a=!0,r=!1){S(t)&&P(t,(t,o)=>{let i=e[t];if(i!==o){if(r){if(null==i&&null!=o){"object"==typeof o&&o.constructor===Object&&(i={},e[t]=i)}}H(o)&&H(i)&&!Array.isArray(i)?I(i,o,a,r):(a||void 0!==o)&&(e[t]=o)}})}function G(e,t,a){if(!t||!e)return;if(!a)return e[t];const r=t.split(".");let o=e;for(let e=0;e{"object"!=typeof e[a]||t.includes(a)||(e[a]=void 0)});const r=Object.getPrototypeOf(e),o={};Object.getOwnPropertyNames(r).forEach(e=>{if("function"==typeof r[e]&&!t.includes(e)){const t=()=>{console.warn((e=>`AG Grid: Grid API function ${e}() cannot be called as the grid has been destroyed.\n It is recommended to remove local references to the grid api. Alternatively, check gridApi.isDestroyed() to avoid calling methods against a destroyed grid.\n To run logic when the grid is about to be destroyed use the gridPreDestroy event. See: ${a}`)(e))};o[e]={value:t,writable:!0}}}),Object.defineProperties(e,o)}function H(e){return"object"==typeof e&&null!==e}const _={};function B(e,t){_[t]||(e(),_[t]=!0)}function q(e){B(()=>console.warn("AG Grid: "+e),e)}function W(e){B(()=>console.error("AG Grid: "+e),e)}function U(e){if(e.name)return e.name;const t=/function\s+([^\(]+)/.exec(e.toString());return t&&2===t.length?t[1].trim():null}function j(e){return!!(e&&e.constructor&&e.call&&e.apply)}function K(e){X(e,400)}const Y=[];let Q=!1;function J(e){Y.push(e),Q||(Q=!0,window.setTimeout(()=>{const e=Y.slice();Y.length=0,Q=!1,e.forEach(e=>e())},0))}function X(e,t=0){e.length>0&&window.setTimeout(()=>e.forEach(e=>e()),t)}function Z(e,t){let a;return function(...r){const o=this;window.clearTimeout(a),a=window.setTimeout((function(){e.apply(o,r)}),t)}}function $(e,t){let a=0;return function(...r){const o=(new Date).getTime();o-a{const l=(new Date).getTime()-o>a;(e()||l)&&(t(),n=!0,null!=i&&(window.clearInterval(i),i=null),l&&r&&console.warn(r))};l(),n||(i=window.setInterval(l,10))}function te(...e){return t=>e.reduce((e,t)=>t(e),t)}const ae=()=>{};var re;!function(e){e.CommunityCoreModule="@ag-grid-community/core",e.InfiniteRowModelModule="@ag-grid-community/infinite-row-model",e.ClientSideRowModelModule="@ag-grid-community/client-side-row-model",e.CsvExportModule="@ag-grid-community/csv-export",e.EnterpriseCoreModule="@ag-grid-enterprise/core",e.RowGroupingModule="@ag-grid-enterprise/row-grouping",e.ColumnsToolPanelModule="@ag-grid-enterprise/column-tool-panel",e.FiltersToolPanelModule="@ag-grid-enterprise/filter-tool-panel",e.MenuModule="@ag-grid-enterprise/menu",e.SetFilterModule="@ag-grid-enterprise/set-filter",e.MultiFilterModule="@ag-grid-enterprise/multi-filter",e.StatusBarModule="@ag-grid-enterprise/status-bar",e.SideBarModule="@ag-grid-enterprise/side-bar",e.RangeSelectionModule="@ag-grid-enterprise/range-selection",e.MasterDetailModule="@ag-grid-enterprise/master-detail",e.RichSelectModule="@ag-grid-enterprise/rich-select",e.GridChartsModule="@ag-grid-enterprise/charts",e.ViewportRowModelModule="@ag-grid-enterprise/viewport-row-model",e.ServerSideRowModelModule="@ag-grid-enterprise/server-side-row-model",e.ExcelExportModule="@ag-grid-enterprise/excel-export",e.ClipboardModule="@ag-grid-enterprise/clipboard",e.SparklinesModule="@ag-grid-enterprise/sparklines",e.AdvancedFilterModule="@ag-grid-enterprise/advanced-filter",e.AngularModule="@ag-grid-community/angular",e.ReactModule="@ag-grid-community/react",e.VueModule="@ag-grid-community/vue"}(re||(re={}));class oe{static register(e){oe.__register(e,!0,void 0)}static registerModules(e){oe.__registerModules(e,!0,void 0)}static __register(e,t,a){oe.runVersionChecks(e),void 0!==a?(oe.areGridScopedModules=!0,void 0===oe.gridModulesMap[a]&&(oe.gridModulesMap[a]={}),oe.gridModulesMap[a][e.moduleName]=e):oe.globalModulesMap[e.moduleName]=e,oe.setModuleBased(t)}static __unRegisterGridModules(e){delete oe.gridModulesMap[e]}static __registerModules(e,t,a){oe.setModuleBased(t),e&&e.forEach(e=>oe.__register(e,t,a))}static isValidModuleVersion(e){const[t,a]=e.version.split(".")||[],[r,o]=oe.currentModuleVersion.split(".")||[];return t===r&&a===o}static runVersionChecks(e){if(oe.currentModuleVersion||(oe.currentModuleVersion=e.version),e.version?oe.isValidModuleVersion(e)||console.error(`AG Grid: You are using incompatible versions of AG Grid modules. Major and minor versions should always match across modules. '${e.moduleName}' is version ${e.version} but the other modules are version ${this.currentModuleVersion}. Please update all modules to the same version.`):console.error(`AG Grid: You are using incompatible versions of AG Grid modules. Major and minor versions should always match across modules. '${e.moduleName}' is incompatible. Please update all modules to the same version.`),e.validate){const t=e.validate();if(!t.isValid){const e=t;console.error("AG Grid: "+e.message)}}}static setModuleBased(e){void 0===oe.moduleBased?oe.moduleBased=e:oe.moduleBased!==e&&B(()=>{console.warn("AG Grid: You are mixing modules (i.e. @ag-grid-community/core) and packages (ag-grid-community) - you can only use one or the other of these mechanisms."),console.warn("Please see https://www.ag-grid.com/javascript-grid/packages-modules/ for more information.")},"ModulePackageCheck")}static __setIsBundled(){oe.isBundled=!0}static __assertRegistered(e,t,a){var r;if(this.__isRegistered(e,a))return!0;const o=t+e;let i;if(oe.isBundled)i=`AG Grid: unable to use ${t} as 'ag-grid-enterprise' has not been loaded. Check you are using the Enterprise bundle:\n \n - - - diff --git a/site/info/uce-starter/js/u-events.js b/site/info/uce-starter/js/u-events.js deleted file mode 100755 index 3a0d4fe..0000000 --- a/site/info/uce-starter/js/u-events.js +++ /dev/null @@ -1,92 +0,0 @@ -(function (root, factory) { - if (typeof exports === 'object' && typeof module !== 'undefined') { - module.exports = factory(); - } else if (typeof define === 'function' && define.amd) { - define([], factory); - } else { - root.EventEmitter = factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { - -class EventEmitter { - constructor() { - /** Map> */ - this._topics = new Map(); - } - - /** - * Subscribe to `topic`. If `slot_key` is provided (truthy), - * it dedupes by that key; otherwise a unique Symbol is used. - * Returns an unsubscribe fn. - */ - on(topic, handler, slot_key = null) { - let map = this._topics.get(topic); - if (!map) { - map = new Map(); - this._topics.set(topic, map); - } - // use the provided slot_key or a fresh Symbol() - const key = slot_key != null ? slot_key : Symbol(); - map.set(key, handler); - return () => this.off(topic, key); - } - - /** - * Unsubscribe by handler function or by slot_key. - */ - off(topic, handlerOrSlotKey) { - const map = this._topics.get(topic); - if (!map) return; - - // if it matches a slotKey directly, remove it - if (map.has(handlerOrSlotKey)) { - map.delete(handlerOrSlotKey); - } else { - // otherwise assume it's a function: remove all matching fns - for (const [key, fn] of map.entries()) { - if (fn === handlerOrSlotKey) { - map.delete(key); - } - } - } - - if (map.size === 0) { - this._topics.delete(topic); - } - } - - /** - * Emit to all handlers on `topic`. Handlers returning - * 'remove_handler' are auto-removed. - * Returns the number of handlers invoked. - */ - emit(topic, ...args) { - let count = 0; - const map = this._topics.get(topic); - if (!map) return count; - - for (const [key, fn] of Array.from(map.entries())) { - const res = fn(...args); - count++; - if (res === 'remove_handler') { - map.delete(key); - } - } - - if (map.size === 0) { - this._topics.delete(topic); - } - return count; - } - - clear(topic) { - if (topic) { - this._topics.delete(topic); - } - return this; - } -} - -return EventEmitter; - -})); diff --git a/site/info/uce-starter/js/u-format.js b/site/info/uce-starter/js/u-format.js deleted file mode 100644 index a10b75c..0000000 --- a/site/info/uce-starter/js/u-format.js +++ /dev/null @@ -1,136 +0,0 @@ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof module === 'object' && module.exports) { - module.exports = factory(); - } else { - root.UFormat = factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { - 'use strict'; - - const BYTE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; - - function scaleBytes(bytes) { - let value = Number(bytes || 0); - let unitIndex = 0; - while (Math.abs(value) >= 1024 && unitIndex < BYTE_UNITS.length - 1) { - value /= 1024; - unitIndex += 1; - } - return { value, unitIndex }; - } - - function formatBytes(bytes) { - if (bytes == null || bytes === '') return '--'; - const scaled = scaleBytes(bytes); - const decimals = scaled.unitIndex === 0 ? 0 : 1; - return `${scaled.value.toFixed(decimals)} ${BYTE_UNITS[scaled.unitIndex]}`; - } - - function formatDiskBytes(bytes) { - if (bytes == null || bytes === '') return '--'; - const scaled = scaleBytes(bytes); - const decimals = scaled.unitIndex >= 4 ? 2 : scaled.unitIndex >= 1 ? 1 : 0; - return `${scaled.value.toFixed(decimals)} ${BYTE_UNITS[scaled.unitIndex]}`; - } - - function formatCount(value) { - const number = Number(value); - if (!Number.isFinite(number)) return '--'; - return number.toLocaleString(); - } - - function formatDurationMs(value) { - const number = Number(value); - if (!Number.isFinite(number)) return '--'; - if (Math.abs(number) >= 1000) { - return `${(number / 1000).toFixed(number >= 10000 ? 0 : 1)} s`; - } - return `${number.toFixed(number >= 100 ? 0 : 1)} ms`; - } - - function parseUnitNumber(text) { - const normalized = String(text || '').trim().toLowerCase().replace(/,/g, ''); - if (!normalized) return null; - - const pure = normalized.match(/^([-+]?\d*\.?\d+)$/); - if (pure) { - return Number(pure[1]); - } - - const withUnit = normalized.match(/^([-+]?\d*\.?\d+)\s*([a-z%][a-z0-9\/_-]*)$/); - if (!withUnit) { - return null; - } - - const value = Number(withUnit[1]); - let unit = withUnit[2]; - if (!Number.isFinite(value)) { - return null; - } - - if (unit.endsWith('/s')) { - unit = unit.slice(0, -2); - } - - const bytes = { - b: 1, - kb: 1024, - kib: 1024, - mb: 1024 ** 2, - mib: 1024 ** 2, - gb: 1024 ** 3, - gib: 1024 ** 3, - tb: 1024 ** 4, - tib: 1024 ** 4, - pb: 1024 ** 5, - pib: 1024 ** 5, - }; - - if (Object.prototype.hasOwnProperty.call(bytes, unit)) { - return value * bytes[unit]; - } - - const durations = { - ms: 0.001, - s: 1, - sec: 1, - secs: 1, - second: 1, - seconds: 1, - m: 60, - min: 60, - mins: 60, - minute: 60, - minutes: 60, - h: 3600, - hr: 3600, - hrs: 3600, - hour: 3600, - hours: 3600, - d: 86400, - day: 86400, - days: 86400, - }; - - if (Object.prototype.hasOwnProperty.call(durations, unit)) { - return value * durations[unit]; - } - - if (unit === '%') { - return value; - } - - return null; - } - - return { - formatBytes, - formatCount, - formatDiskBytes, - formatDurationMs, - parseUnitNumber, - scaleBytes, - }; -})); \ No newline at end of file diff --git a/site/info/uce-starter/js/u-howler-demo.html b/site/info/uce-starter/js/u-howler-demo.html deleted file mode 100755 index 7d86387..0000000 --- a/site/info/uce-starter/js/u-howler-demo.html +++ /dev/null @@ -1,1488 +0,0 @@ - - - - - - U-Howler.js Demo - - - -
-

U-Howler.js Demo

- -
-
-

Basic Controls

-
-
-
-
-
-
-
- - - - -
- -
- - - 440 Hz -
- -
- - - 1.0 -
-
- -
-
- - -
- -
-
- -
-

Global Controls

-
- - -
- -
- - - 1.0 -
-
-
- -
-

API Overview

- -
-

Howler (Global)

-
volume(vol?) → Howler|number
-
mute(muted?) → Howler
-
stop() → Howler
-
unload() → Howler
-
codecs(ext) → boolean
-
environment(env) → Howler
-
- -
-

Howl Constructor

-
new Howl(options)
-
- Options: src, volume, rate, loop, mute, preload, autoplay, sprite, format, html5, pool, xhr, spatial, on* -
-
- -
-

Core Methods

-
load() → Promise<Howl>
-
play(sprite?) → number|Promise
-
pause(id?) → Howl
-
stop(id?) → Howl
-
mute(muted?, id?) → Howl|boolean
-
volume(vol?, id?) → Howl|number
-
fade(from, to, duration, id?) → Howl
-
rate(rate?, id?) → Howl|number
-
seek(seek?, id?) → Howl|number
-
- -
-

Examples

-
-// Promise support
-const howl = new Howl({src: 'audio.mp3'});
-await howl.load();
-const id = howl.play();
-
-// Sprite usage
-const soundFx = new Howl({
-  src: 'sounds.mp3',
-  sprite: {
-    jump: [0, 500],
-    shoot: [600, 300]
-  }
-});
-soundFx.play('jump');
-
-
-
-
- -
-
-

Audio Sprites

-
-

Audio Sprites Demo

-
-
-
-
-
- -
- - -
- -
- - - - - - - - -
- -
-
- -
-

Audio Sprites API

- -
-

Sprite Methods

-
play(spriteName) → number
-
- Play a specific sprite by name from the sprite collection. -
-
- -
-

Sprite Configuration

-
- Sprite Format: { name: [start_ms, duration_ms] }
- • start_ms: Starting position in milliseconds
- • duration_ms: Length of the sprite in milliseconds
- • Sprites can be tightly packed or have gaps between them
-
-
-const spriteMap = {
-  jump: [0, 500],       // 0ms - 500ms
-  coin: [500, 300],     // 500ms - 800ms
-  laser: [800, 400],    // 800ms - 1200ms
-  explosion: [1200, 800] // 1200ms - 2000ms
-};
-
-const gameAudio = new Howl({
-  src: 'game-sounds.wav',
-  sprite: spriteMap
-});
-
-gameAudio.play('jump');
-
-
-
-
- -
-
-

Audio Effects

-
-

Filters

-
- - - - - - -
-
- - -
-
- -
-
-

Rate Control

-
- - - 1.0x -
- -
- -
-

Fade Effects

-
- - -
-
-
-
- -
-

Effects API

- -
-

Effect Methods

-
addEffect(type, options?) → AudioNode
-
effectsArray<AudioNode>
-
updateEffectsChain() → Howl
-
enableEQ(bands?, callback?, boost?) → Howl
-
disableEQ() → Howl
-
- -
-

Audio Effects

-
- addEffect(type, options) - Add audio effect to the sound
- • Returns the Web Audio node for direct manipulation
- • Types: 'lowpass', 'highpass', 'bandpass', 'notch', 'delay', 'reverb', 'gain', 'distortion'
- • Options vary by type (frequency, Q, delay, gain, etc.)

- effects - Getter for effects array (for direct manipulation)
- updateEffectsChain() - Rebuild audio chain after effects manipulation -
-
-// Add effects and manipulate them
-const filter = howl.addEffect('lowpass', {
-  frequency: 1000, Q: 1
-});
-
-// Direct effects array manipulation
-howl.effects.splice(1, 1); // Remove delay effect
-howl.effects.reverse(); // Reorder effects
-howl.updateEffectsChain(); // Apply changes
-
-
- -
-

Frequency Analysis

-
- enableEQ(bands, callback, boost) - Enable real-time frequency analysis
- • bands: Number of frequency bands (default: 16)
- • callback: Function called with frequency data array
- • boost: Gain multiplier for visualization (default: 4.0)

- disableEQ() - Disable frequency analysis
-
-
-
-
- -
-
-

3D Spatial Audio

-
-
-
-
-
-
-
- 🟢 Green is you! - Drag the dots to move them around the 3D space! - 🏛️ Cathedral environment provides realistic reverb. -
-
- - -
-
-
- -
-

Spatial API

- -
-

3D Spatial Audio

-
- spatial - Object containing 3D audio properties
- • Properties: position{x,y,z}, orientation{x,y,z}, velocity{x,y,z}
- • distance{ref, max, rolloff, model}, cone{inner, outer, outerGain}
- • occlusion, obstruction, panningModel

- Howler.listener - Global listener (camera/player) object
- Howler.environment(env) - Set reverb environment
- • Accepts preset strings: 'room', 'hall', 'cathedral'
- • Or custom objects: { size, decay, dampening }
- • Pass null to disable environment reverb -
-
- -
-

Environment Presets

-
- Built-in Reverb Environments: 'room', 'hall', 'cathedral', 'cave', 'underwater'

- - Custom Environment Parameters:
- • size: 'small' | 'medium' | 'large' - Room size
- • decay: 0.1-20.0 - Reverb tail length in seconds
- • dampening: 0.0-1.0 - High frequency absorption (0=bright, 1=muffled) -
-
- -
-

Spatial Examples

-
-const spatial = new Howl({
-  src: 'footsteps.mp3',
-  spatial: {
-    position: [10, 0, -5],
-    distance: { ref: 2, max: 100 },
-    cone: { inner: 45, outer: 90, outerGain: 0.2 }
-  }
-});
-
-Howler.listener.position = { x: 0, y: 1.8, z: 0 };
-Howler.listener.update();
-
-spatial.spatial.position = { x: enemy.x, y: enemy.y, z: enemy.z };
-spatial.spatial.update();
-
-// Built-in presets
-Howler.environment('room');      // Small room reverb
-Howler.environment('hall');      // Medium hall reverb
-Howler.environment('cathedral'); // Large cathedral reverb
-
-// Custom environment
-Howler.environment({
-  size: 'medium',
-  decay: 3.0,
-  dampening: 0.4
-});
-
-Howler.environment(null); // Disable environment
-
-
-
-
- -
-
-

Library Info

-
-
Loading library information...
- -

Supported Codecs:

-
-
-
- -
-

Events & Utilities

- -
-

Event Listeners

-
on(event, fn, id?) → Howl
-
off(event?, fn?, id?) → Howl
-
once(event, fn, id?) → Howl
-
- -
-

Utility Methods

-
playing(id?) → boolean
-
duration(id?) → number
-
state() → string
-
unload() → null
-
- -
-

Events

-
load() - Audio loaded successfully
-
loaderror(id, error) - Failed to load audio
-
play(id) - Sound started playing
-
pause(id) - Sound paused
-
stop(id) - Sound stopped
-
end(id) - Sound finished playing
-
fade(id) - Fade effect completed
-
volume(id) - Volume changed
-
rate(id) - Playback rate changed
-
seek(id) - Playback position changed
-
mute(id) - Mute state changed
-
unlock() - Audio context unlocked (user interaction)
-
playerror(id, error) - Playback error occurred
-
-
-
-
- - - - - diff --git a/site/info/uce-starter/js/u-howler.js b/site/info/uce-starter/js/u-howler.js deleted file mode 100755 index d322751..0000000 --- a/site/info/uce-starter/js/u-howler.js +++ /dev/null @@ -1,1162 +0,0 @@ -(function (root, factory) { - if (typeof exports === 'object' && typeof module !== 'undefined') { - var exports_obj = factory(); - module.exports = exports_obj; - } else if (typeof define === 'function' && define.amd) { - define([], factory); - } else { - var exports_obj = factory(); - root.Howler = exports_obj.Howler; - root.Howl = exports_obj.Howl; - } -}(typeof self !== 'undefined' ? self : this, function () { - -/** - * based on Howler.js - (c) 2013-2020, James Simpson of GoldFire Studios - * Mostly compatible API - */ - -class HowlerGlobal { - constructor() { - this._counter = 1000; - this._howls = []; - this._volume = 1; - this._muted = false; - this._html5Pool = []; - this._codecs = {}; - this.ctx = null; - this.masterGain = null; - this.usingWebAudio = true; - this.autoUnlock = true; - this._audioUnlocked = false; - this._environment = null; - this._setup(); - } - - volume(vol) { - if (vol === undefined) return this._volume; - this._volume = Math.max(0, Math.min(1, vol)); - - if (!this._muted) { - if (this.usingWebAudio && this.masterGain) { - this.masterGain.gain.setValueAtTime(this._volume, this.ctx.currentTime); - } - this._howls.forEach(howl => howl._updateVolume()); - } - return this; - } - - mute(muted = true) { - this._muted = muted; - let vol = muted ? 0 : this._volume; - - if (this.usingWebAudio && this.masterGain) { - this.masterGain.gain.setValueAtTime(vol, this.ctx.currentTime); - } - this._howls.forEach(howl => howl._updateVolume()); - return this; - } - - stop() { - this._howls.forEach(howl => howl.stop()); - return this; - } - - unload() { - this._howls.slice().forEach(howl => howl.unload()); - if (this.ctx?.close) { - this.ctx.close(); - this.ctx = null; - this._setupAudioContext(); - } - return this; - } - - codecs(ext) { - return this._codecs[ext?.replace(/^x-/, '')]; - } - - _setup() { - this._setupAudioContext(); - this._setupCodecs(); - if (this.autoUnlock) this._setupUnlock(); - } - - _setupAudioContext() { - if (!this.usingWebAudio) return; - - try { - this.ctx = new (window.AudioContext || window.webkitAudioContext)(); - this.masterGain = this.ctx.createGain(); - this.masterGain.connect(this.ctx.destination); - this.masterGain.gain.setValueAtTime(this._muted ? 0 : this._volume, this.ctx.currentTime); - - this.listener = { - position: { x: 0, y: 0, z: 0 }, - orientation: { - forward: { x: 0, y: 0, z: -1 }, - up: { x: 0, y: 1, z: 0 } - }, - velocity: { x: 0, y: 0, z: 0 }, - update: () => this._updateListener() - }; - } catch (e) { - this.usingWebAudio = false; - } - } - - _setupCodecs() { - if (typeof Audio === 'undefined') return; - - let audio = new Audio(); - let test = (mime) => !!audio.canPlayType(mime).replace(/^no$/, ''); - - this._codecs = { - mp3: test('audio/mpeg;'), - opus: test('audio/ogg; codecs="opus"'), - ogg: test('audio/ogg; codecs="vorbis"'), - wav: test('audio/wav; codecs="1"') || test('audio/wav'), - aac: test('audio/aac;'), - m4a: test('audio/x-m4a;') || test('audio/m4a;') || test('audio/aac;'), - mp4: test('audio/x-mp4;') || test('audio/mp4;') || test('audio/aac;'), - webm: test('audio/webm; codecs="vorbis"'), - flac: test('audio/x-flac;') || test('audio/flac;') - }; - } - - _setupUnlock() { - if (this._audioUnlocked || !this.ctx) return; - - let unlock = () => { - if (this._audioUnlocked) return; - - let buffer = this.ctx.createBuffer(1, 1, 22050); - let source = this.ctx.createBufferSource(); - source.buffer = buffer; - source.connect(this.ctx.destination); - source.start(0); - - if (this.ctx.resume) this.ctx.resume(); - - source.onended = () => { - this._audioUnlocked = true; - document.removeEventListener('touchstart', unlock, true); - document.removeEventListener('click', unlock, true); - this._howls.forEach(howl => howl._emit('unlock')); - }; - }; - - document.addEventListener('touchstart', unlock, true); - document.addEventListener('click', unlock, true); - } - - _getHtml5Audio() { - return this._html5Pool.pop() || new Audio(); - } - - _releaseHtml5Audio(audio) { - if (audio._unlocked && this._html5Pool.length < 10) { - this._html5Pool.push(audio); - } - } - - environment(env) { - if(!env) - return this._environment; - if (typeof env === 'string') { - let presets = { - room: { size: 'small', decay: 1.5, dampening: 0.8 }, - hall: { size: 'medium', decay: 2.5, dampening: 0.6 }, - cathedral: { size: 'large', decay: 8.0, dampening: 0.1 }, - cave: { size: 'large', decay: 6.0, dampening: 0.2 }, - underwater: { size: 'medium', decay: 3.0, dampening: 0.9 } - }; - this._environment = presets[env] || null; - } else { - this._environment = env; - } - this._howls.forEach(howl => howl._updateEnvironment?.()); - return this; - } - - _updateListener() { - if (!this.ctx?.listener) return; - - let { position, orientation, velocity } = this.listener; - let l = this.ctx.listener; - - if (l.positionX) { - l.positionX.setValueAtTime(position.x, this.ctx.currentTime); - l.positionY.setValueAtTime(position.y, this.ctx.currentTime); - l.positionZ.setValueAtTime(position.z, this.ctx.currentTime); - l.forwardX.setValueAtTime(orientation.forward.x, this.ctx.currentTime); - l.forwardY.setValueAtTime(orientation.forward.y, this.ctx.currentTime); - l.forwardZ.setValueAtTime(orientation.forward.z, this.ctx.currentTime); - l.upX.setValueAtTime(orientation.up.x, this.ctx.currentTime); - l.upY.setValueAtTime(orientation.up.y, this.ctx.currentTime); - l.upZ.setValueAtTime(orientation.up.z, this.ctx.currentTime); - } else { - l.setPosition(position.x, position.y, position.z); - l.setOrientation( - orientation.forward.x, orientation.forward.y, orientation.forward.z, - orientation.up.x, orientation.up.y, orientation.up.z - ); - } - - if (l.setVelocity) { - l.setVelocity(velocity.x, velocity.y, velocity.z); - } - } -} - -class Howl { - constructor(options = {}) { - if(options.url) options.src = options.url; // backwards compat - if(options.urls) options.src = options.urls; // backwards compat - if (!options.src?.length) throw new Error('src required'); - - Object.assign(this, { - _src: Array.isArray(options.src) ? options.src : [options.src], - _volume: options.volume ?? 1, - _rate: options.rate ?? 1, - _loop: options.loop ?? false, - _muted: options.mute ?? false, - _preload: options.preload ?? true, - _autoplay: options.autoplay ?? false, - _sprite: options.sprite ?? {}, - _format: options.format ? (Array.isArray(options.format) ? options.format : [options.format]) : null, - _html5: options.html5 ?? false, - _pool: options.pool ?? 5, - _xhr: { method: 'GET', ...options.xhr }, - _duration: 0, - _state: 'unloaded', - _sounds: [], - _queue: [], - _listeners: {}, - _webAudio: Howler.usingWebAudio && !options.html5, - - _analyzer: null, - _frequencyCallback: null, - _frequencyData: null, - _frequencyBands: options.frequencyBands || 16, - _frequencyBoost: 4.0, - _frequencyEnabled: false, - - _effects: [] - }); - - if (options.spatial) { - this.spatial = { - enabled: true, - position: { x: 0, y: 0, z: 0 }, - orientation: { x: 0, y: 0, z: -1 }, - velocity: { x: 0, y: 0, z: 0 }, - distance: { - ref: 1, - max: 10000, - rolloff: 1, - model: 'inverse' - }, - cone: { - inner: 360, - outer: 360, - outerGain: 0 - }, - occlusion: 0, - obstruction: 0, - panningModel: 'HRTF', - update: () => this._updateSpatial() - }; - - if (Array.isArray(options.spatial.position)) { - let [x, y, z] = options.spatial.position; - Object.assign(this.spatial.position, { x, y, z }); - } - if (options.spatial.distance) { - Object.assign(this.spatial.distance, options.spatial.distance); - } - if (options.spatial.cone) { - Object.assign(this.spatial.cone, options.spatial.cone); - } - if (options.spatial.panningModel) { - this.spatial.panningModel = options.spatial.panningModel; - } - } - - ['load', 'loaderror', 'play', 'pause', 'stop', 'end', 'fade', 'volume', 'rate', 'seek', 'mute', 'unlock'].forEach(event => { - if (options[`on${event}`]) this.on(event, options[`on${event}`]); - }); - - Howler._howls.push(this); - - if (this._autoplay) this._queue.push({ event: 'play', action: () => this.play() }); - if (this._preload) this.load(); - } - - load() { - if (this._state !== 'unloaded') return Promise.resolve(this); - - this._state = 'loading'; - - return new Promise((resolve, reject) => { - let url = this._selectSource(); - if (!url) { - let error = 'No compatible source found'; - this._emit('loaderror', null, error); - return reject(new Error(error)); - } - - this._src = url; - - if (this._webAudio) { - this._loadWebAudio(url).then(resolve).catch(reject); - } else { - this._loadHtml5(url).then(resolve).catch(reject); - } - }); - } - - play(sprite) { - if (typeof sprite === 'number') { - let sound = this._sounds.find(s => s._id === sprite); - return sound ? this._playSound(sound) : null; - } - - if (this._state !== 'loaded') { - if (this._state === 'loading') { - return new Promise(resolve => { - this._queue.push({ event: 'play', action: () => resolve(this.play(sprite)) }); - }); - } - return this.load().then(() => this.play(sprite)); - } - - let sound = this._getSound(); - sound._sprite = sprite || '__default'; - return this._playSound(sound); - } - - pause(id) { - this._getSounds(id).forEach(sound => { - if (!sound._paused) { - sound._paused = true; - if (sound._node) { - if (this._webAudio && sound._source) { - sound._source.stop(); - this._cleanupSound(sound); - } else { - sound._node.pause(); - } - } - this._emit('pause', sound._id); - } - }); - return this; - } - - stop(id) { - this._getSounds(id).forEach(sound => { - sound._paused = true; - sound._ended = true; - if (sound._node) { - if (this._webAudio) { - if (sound._source) { - sound._source.stop(); - } - } else { - sound._node.pause(); - sound._node.currentTime = 0; - } - this._cleanupSound(sound); - } - this._emit('stop', sound._id); - }); - return this; - } - - mute(muted, id) { - if (muted === undefined) return this._muted; - - if (id === undefined) this._muted = muted; - - this._getSounds(id).forEach(sound => { - sound._muted = muted; - this._updateSoundVolume(sound); - this._emit('mute', sound._id); - }); - return this; - } - - volume(vol, id) { - if (vol === undefined) { - let sound = id ? this._sounds.find(s => s._id === id) : this._sounds[0]; - return sound ? sound._volume : this._volume; - } - - vol = Math.max(0, Math.min(1, vol)); - if (id === undefined) this._volume = vol; - - this._getSounds(id).forEach(sound => { - sound._volume = vol; - this._updateSoundVolume(sound); - this._emit('volume', sound._id); - }); - return this; - } - - fade(from, to, duration, id) { - this._getSounds(id).forEach(sound => { - sound._volume = from; - this._updateSoundVolume(sound); - - let startTime = Date.now(); - let fadeStep = () => { - let elapsed = Date.now() - startTime; - let progress = Math.min(elapsed / duration, 1); - let currentVol = from + (to - from) * progress; - - sound._volume = currentVol; - this._updateSoundVolume(sound); - - if (progress < 1) { - requestAnimationFrame(fadeStep); - } else { - this._emit('fade', sound._id); - } - }; - - requestAnimationFrame(fadeStep); - }); - return this; - } - - rate(rate, id) { - if (rate === undefined) { - let sound = id ? this._sounds.find(s => s._id === id) : this._sounds[0]; - return sound ? sound._rate : this._rate; - } - - if (id === undefined) this._rate = rate; - - this._getSounds(id).forEach(sound => { - sound._rate = rate; - if (sound._node) { - if (this._webAudio && sound._source) { - sound._source.playbackRate.setValueAtTime(rate, Howler.ctx.currentTime); - } else { - sound._node.playbackRate = rate; - } - } - this._emit('rate', sound._id); - }); - return this; - } - - seek(seek, id) { - if (seek === undefined) { - let sound = id ? this._sounds.find(s => s._id === id) : this._sounds[0]; - if (!sound) return 0; - - if (this._webAudio) { - let elapsed = sound._playStart ? Howler.ctx.currentTime - sound._playStart : 0; - return sound._seek + elapsed * sound._rate; - } - return sound._node?.currentTime || 0; - } - - this._getSounds(id).forEach(sound => { - let wasPlaying = !sound._paused; - if (wasPlaying) this.pause(sound._id); - - sound._seek = seek; - if (!this._webAudio && sound._node) { - sound._node.currentTime = seek; - } - - if (wasPlaying) this.play(sound._id); - this._emit('seek', sound._id); - }); - return this; - } - - playing(id) { - if (id) { - let sound = this._sounds.find(s => s._id === id); - return sound ? !sound._paused : false; - } - return this._sounds.some(s => !s._paused); - } - - duration(id) { - if (id) { - let sound = this._sounds.find(s => s._id === id); - if (sound && this._sprite[sound._sprite]) { - return this._sprite[sound._sprite][1] / 1000; - } - } - return this._duration; - } - - state() { - return this._state; - } - - unload() { - this.stop(); - this._stopFrequencyAnalysis(); - Howler._howls.splice(Howler._howls.indexOf(this), 1); - this._sounds = []; - this._state = 'unloaded'; - return null; - } - - enableEQ(bands = 16, callback, boost = 4.0) { - if (!this._webAudio) { - console.warn('Frequency analysis requires Web Audio API'); - return this; - } - - this._frequencyCallback = callback; - this._frequencyBands = bands; - this._frequencyBoost = boost; - this._frequencyEnabled = true; - - if (!this._analyzer) { - this._analyzer = Howler.ctx.createAnalyser(); - this._analyzer.fftSize = 2048; - this._analyzer.smoothingTimeConstant = 0.3; - this._frequencyData = new Uint8Array(this._analyzer.frequencyBinCount); - this._analyzer.connect(Howler.masterGain); - } - - this._rebuildEffectChain(); - this._startFrequencyAnalysis(); - return this; - } - - disableEQ() { - this._frequencyEnabled = false; - this._stopFrequencyAnalysis(); - this._rebuildEffectChain(); - return this; - } - - getFrequencyData() { - if (!this._analyzer || !this._frequencyEnabled) return null; - - this._analyzer.getByteFrequencyData(this._frequencyData); - - let bands = new Array(this._frequencyBands); - let nyquist = Howler.ctx.sampleRate / 2; - let dataLength = this._frequencyData.length; - - let minFreq = 20; - let maxFreq = nyquist; - let logMin = Math.log(minFreq); - let logMax = Math.log(maxFreq); - let logRange = logMax - logMin; - - for (let i = 0; i < this._frequencyBands; i++) { - // Logarithmic frequency distribution - let logStart = logMin + (i / this._frequencyBands) * logRange; - let logEnd = logMin + ((i + 1) / this._frequencyBands) * logRange; - - let startFreq = Math.exp(logStart); - let endFreq = Math.exp(logEnd); - - let startBin = Math.floor((startFreq / nyquist) * dataLength); - let endBin = Math.ceil((endFreq / nyquist) * dataLength); - - let sum = 0; - let count = 0; - for (let j = startBin; j < Math.min(endBin, dataLength); j++) { - sum += this._frequencyData[j]; - count++; - } - - bands[i] = count > 0 ? (sum / count / 255) : 0; // Normalize to 0-1 - } - - for (let i = 0; i < bands.length; i++) { - bands[i] = Math.min(1.0, bands[i] * this._frequencyBoost); - } - - return bands; - } - - _startFrequencyAnalysis() { - if (!this._frequencyEnabled || this._frequencyAnimationId) return; - - let analyze = () => { - if (!this._frequencyEnabled) return; - - let frequencyData = this.getFrequencyData(); - if (frequencyData && this._frequencyCallback) { - this._frequencyCallback(frequencyData); - } - - this._frequencyAnimationId = requestAnimationFrame(analyze); - }; - - analyze(); - } - - _stopFrequencyAnalysis() { - if (this._frequencyAnimationId) { - cancelAnimationFrame(this._frequencyAnimationId); - this._frequencyAnimationId = null; - } - } - - addEffect(type, options = {}) { - if (!this._webAudio) { - console.warn('Audio effects require Web Audio API'); - return null; - } - - let effect; - - switch (type.toLowerCase()) { - case 'lowpass': - effect = Howler.ctx.createBiquadFilter(); - effect.type = 'lowpass'; - effect.frequency.setValueAtTime(options.frequency || 1000, Howler.ctx.currentTime); - effect.Q.setValueAtTime(options.Q || 1, Howler.ctx.currentTime); - break; - - case 'highpass': - effect = Howler.ctx.createBiquadFilter(); - effect.type = 'highpass'; - effect.frequency.setValueAtTime(options.frequency || 300, Howler.ctx.currentTime); - effect.Q.setValueAtTime(options.Q || 1, Howler.ctx.currentTime); - break; - - case 'bandpass': - effect = Howler.ctx.createBiquadFilter(); - effect.type = 'bandpass'; - effect.frequency.setValueAtTime(options.frequency || 1000, Howler.ctx.currentTime); - effect.Q.setValueAtTime(options.Q || 1, Howler.ctx.currentTime); - break; - - case 'notch': - effect = Howler.ctx.createBiquadFilter(); - effect.type = 'notch'; - effect.frequency.setValueAtTime(options.frequency || 1000, Howler.ctx.currentTime); - effect.Q.setValueAtTime(options.Q || 30, Howler.ctx.currentTime); - break; - - case 'delay': - effect = Howler.ctx.createDelay(options.maxDelay || 1); - effect.delayTime.setValueAtTime(options.delay || 0.3, Howler.ctx.currentTime); - break; - - case 'reverb': - effect = Howler.ctx.createConvolver(); - let length = Howler.ctx.sampleRate * (options.duration || 2); - let impulse = Howler.ctx.createBuffer(2, length, Howler.ctx.sampleRate); - let decay = options.decay || 2; - - for (let channel = 0; channel < 2; channel++) { - let channelData = impulse.getChannelData(channel); - for (let i = 0; i < length; i++) { - channelData[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / length, decay); - } - } - effect.buffer = impulse; - break; - - case 'gain': - effect = Howler.ctx.createGain(); - effect.gain.setValueAtTime(options.gain || 1, Howler.ctx.currentTime); - break; - - case 'distortion': - effect = Howler.ctx.createWaveShaper(); - let samples = 44100; - let curve = new Float32Array(samples); - let amount = options.amount || 50; - for (let i = 0; i < samples; i++) { - let x = (i * 2) / samples - 1; - curve[i] = ((3 + amount) * x * 20 * Math.PI / 180) / (Math.PI + amount * Math.abs(x)); - } - effect.curve = curve; - effect.oversample = options.oversample || '4x'; - break; - - default: - console.warn(`Unknown effect type: ${type}`); - return null; - } - - if (effect) { - this._effects.push(effect); - this._rebuildEffectChain(); - } - - return effect; - } - - get effects() { - return this._effects; - } - - updateEffectsChain() { - this._rebuildEffectChain(); - return this; - } - - _rebuildEffectChain() { - this._sounds.forEach(sound => { - if (sound._node && this._webAudio) { - let startNode = sound._panner || sound._node; - this._connectSoundToChain(sound, startNode); - } - }); - } - - _connectSoundToChain(sound, startNode = null) { - if (!sound._node || !this._webAudio) return; - - let sourceNode = startNode || sound._node; - sourceNode.disconnect(); - - let currentNode = sourceNode; - - this._effects.forEach(effect => { - currentNode.connect(effect); - currentNode = effect; - }); - - if (this._environmentReverb && sound._panner) { - this._ensureEnvironmentSend(sound); - currentNode.connect(sound._environmentSend); - sound._environmentSend.connect(this._environmentReverb); - } - - if (this._analyzer && this._frequencyEnabled) { - currentNode.connect(this._analyzer); - sound._analyzerConnected = true; - } else { - currentNode.connect(Howler.masterGain); - sound._analyzerConnected = false; - } - } - - _ensureEnvironmentSend(sound) { - if (!sound._environmentSend) { - sound._environmentSend = Howler.ctx.createGain(); - sound._environmentSend.gain.setValueAtTime(0.7, Howler.ctx.currentTime); - } - } - - on(event, fn, id) { - (this._listeners[event] = this._listeners[event] || []).push({ fn, id }); - return this; - } - - off(event, fn, id) { - let listeners = this._listeners[event]; - if (!listeners) return this; - - if (!fn && !id) { - this._listeners[event] = []; - } else { - this._listeners[event] = listeners.filter(l => - (fn && l.fn !== fn) || (id && l.id !== id) - ); - } - return this; - } - - once(event, fn, id) { - let onceFn = (...args) => { - fn(...args); - this.off(event, onceFn, id); - }; - return this.on(event, onceFn, id); - } - - _selectSource() { - for (let src of this._src) { - let ext = this._format?.[this._src.indexOf(src)] || - src.match(/\.([^.?]+)(\?|$)/)?.[1] || - src.match(/^data:audio\/([^;,]+)/)?.[1]; - - if (ext && Howler.codecs(ext)) return src; - } - return null; - } - - async _loadWebAudio(url) { - try { - let arrayBuffer; - - if (url.startsWith('data:')) { - let data = atob(url.split(',')[1]); - arrayBuffer = new Uint8Array(data.length); - for (let i = 0; i < data.length; i++) { - arrayBuffer[i] = data.charCodeAt(i); - } - arrayBuffer = arrayBuffer.buffer; - } else { - let response = await fetch(url, this._xhr); - arrayBuffer = await response.arrayBuffer(); - } - - let audioBuffer = await Howler.ctx.decodeAudioData(arrayBuffer); - this._buffer = audioBuffer; - this._duration = audioBuffer.duration; - this._finishLoad(); - return this; - } catch (error) { - this._emit('loaderror', null, error.message); - throw error; - } - } - - async _loadHtml5(url) { - return new Promise((resolve, reject) => { - let audio = Howler._getHtml5Audio(); - - let onLoad = () => { - this._duration = Math.ceil(audio.duration * 10) / 10; - this._finishLoad(); - audio.removeEventListener('canplaythrough', onLoad); - audio.removeEventListener('error', onError); - resolve(this); - }; - - let onError = () => { - let error = `Failed to load: ${url}`; - audio.removeEventListener('canplaythrough', onLoad); - audio.removeEventListener('error', onError); - this._emit('loaderror', null, error); - reject(new Error(error)); - }; - - audio.addEventListener('canplaythrough', onLoad); - audio.addEventListener('error', onError); - audio.src = url; - audio.load(); - }); - } - - _finishLoad() { - if (!Object.keys(this._sprite).length) { - this._sprite = { __default: [0, this._duration * 1000] }; - } - - this._state = 'loaded'; - this._emit('load'); - this._processQueue(); - } - - _processQueue() { - if (this._queue.length) { - let { action } = this._queue.shift(); - action(); - this._processQueue(); - } - } - - _getSound() { - let sound = this._sounds.find(s => s._ended); - - if (!sound) { - if (this._sounds.length >= this._pool) { - return this._sounds.find(s => s._paused) || this._sounds[0]; - } - sound = this._createSound(); - } - - return this._resetSound(sound); - } - - _createSound() { - let sound = { - _id: ++Howler._counter, - _volume: this._volume, - _rate: this._rate, - _seek: 0, - _paused: true, - _ended: true, - _muted: this._muted, - _sprite: '__default' - }; - - this._sounds.push(sound); - this._createSoundNode(sound); - return sound; - } - - _resetSound(sound) { - Object.assign(sound, { - _volume: this._volume, - _rate: this._rate, - _seek: 0, - _paused: true, - _ended: true, - _muted: this._muted, - _sprite: '__default' - }); - return sound; - } - - _createSoundNode(sound) { - if (this._webAudio) { - sound._node = Howler.ctx.createGain(); - - if (this.spatial?.enabled) { - sound._panner = Howler.ctx.createPanner(); - // Set the panning model (this doesn't change dynamically) - sound._panner.panningModel = this.spatial.panningModel; - sound._node.connect(sound._panner); - this._updateSoundSpatial(sound); - - if (Howler._environment) { - this._updateEnvironment(); - } - - this._connectSoundToChain(sound, sound._panner); - } else { - this._connectSoundToChain(sound); - } - } else { - sound._node = Howler._getHtml5Audio(); - sound._node.src = this._src; - } - } - - _playSound(sound) { - if (!sound || this._state !== 'loaded') return null; - - let sprite = this._sprite[sound._sprite]; - if (!sprite) return null; - - let [start, duration] = sprite; - let seek = Math.max(0, sound._seek || start / 1000); - - sound._paused = false; - sound._ended = false; - - if (this._webAudio) { - this._playWebAudio(sound, seek, duration / 1000); - } else { - this._playHtml5(sound, seek); - } - - this._emit('play', sound._id); - return sound._id; - } - - _playWebAudio(sound, seek, duration) { - this._cleanupSound(sound); - - sound._source = Howler.ctx.createBufferSource(); - sound._source.buffer = this._buffer; - sound._source.connect(sound._node); - - sound._source.playbackRate.setValueAtTime(sound._rate, Howler.ctx.currentTime); - sound._playStart = Howler.ctx.currentTime; - - if (sound._loop) { - sound._source.loop = true; - sound._source.start(0, seek); - } else { - // Fix: duration is the sprite duration, not total audio duration - sound._source.start(0, seek, duration); - sound._source.onended = () => this._onSoundEnd(sound); - } - - this._updateSoundVolume(sound); - } - - _playHtml5(sound, seek) { - let { _node: node } = sound; - node.currentTime = seek; - node.volume = this._getEffectiveVolume(sound); - node.playbackRate = sound._rate; - node.muted = sound._muted || this._muted || Howler._muted; - - let promise = node.play(); - if (promise) { - promise.catch(() => this._emit('playerror', sound._id, 'Playback failed')); - } - - if (!sound._loop) { - node.onended = () => this._onSoundEnd(sound); - } - } - - _onSoundEnd(sound) { - sound._paused = true; - sound._ended = true; - this._emit('end', sound._id); - - if (sound._loop) { - sound._ended = false; - this._playSound(sound); - } - } - - _updateSoundVolume(sound) { - if (!sound._node) return; - - let volume = this._getEffectiveVolume(sound); - - if (this._webAudio) { - sound._node.gain.setValueAtTime(volume, Howler.ctx.currentTime); - } else { - sound._node.volume = volume; - } - } - - _getEffectiveVolume(sound) { - if (sound._muted || this._muted || Howler._muted) return 0; - return sound._volume * this._volume * Howler._volume; - } - - _updateVolume() { - this._sounds.forEach(sound => this._updateSoundVolume(sound)); - } - - _cleanupSound(sound) { - if (sound._source) { - sound._source.disconnect(); - sound._source = null; - } - if (sound._occlusionFilter) { - sound._occlusionFilter.disconnect(); - sound._occlusionFilter = null; - } - } - - _getSounds(id) { - return id ? this._sounds.filter(s => s._id === id) : this._sounds; - } - - _emit(event, id, data) { - let listeners = this._listeners[event]; - if (!listeners) return; - - listeners.forEach(({ fn, id: listenerId }) => { - if (!listenerId || listenerId === id) { - setTimeout(() => fn(id, data), 0); - } - }); - } - - _updateSpatial() { - if (!this.spatial?.enabled) return; - - this._sounds.forEach(sound => { - if (sound._panner) { - this._updateSoundSpatial(sound); - } - }); - } - - _updateSoundSpatial(sound) { - if (!sound._panner || !this.spatial?.enabled) return; - - let { position, orientation, velocity, distance, cone, occlusion, obstruction } = this.spatial; - let p = sound._panner; - - if (p.positionX) { - p.positionX.setValueAtTime(position.x, Howler.ctx.currentTime); - p.positionY.setValueAtTime(position.y, Howler.ctx.currentTime); - p.positionZ.setValueAtTime(position.z, Howler.ctx.currentTime); - p.orientationX.setValueAtTime(orientation.x, Howler.ctx.currentTime); - p.orientationY.setValueAtTime(orientation.y, Howler.ctx.currentTime); - p.orientationZ.setValueAtTime(orientation.z, Howler.ctx.currentTime); - } else { - p.setPosition(position.x, position.y, position.z); - p.setOrientation(orientation.x, orientation.y, orientation.z); - } - - if (p.setVelocity && velocity) { - p.setVelocity(velocity.x, velocity.y, velocity.z); - } - - p.refDistance = distance.ref; - p.maxDistance = distance.max; - p.rolloffFactor = distance.rolloff; - p.distanceModel = distance.model; - - p.coneInnerAngle = cone.inner; - p.coneOuterAngle = cone.outer; - p.coneOuterGain = cone.outerGain; - - this._applyOcclusion(sound, occlusion || 0, obstruction || 0); - } - - _applyOcclusion(sound, occlusion, obstruction) { - if (!sound._occlusionFilter && (occlusion > 0 || obstruction > 0)) { - sound._occlusionFilter = Howler.ctx.createBiquadFilter(); - sound._occlusionFilter.type = 'lowpass'; - sound._node.disconnect(); - sound._node.connect(sound._occlusionFilter); - sound._occlusionFilter.connect(sound._panner || Howler.masterGain); - } - - if (sound._occlusionFilter) { - let freq = 20000 * (1 - Math.max(occlusion, obstruction) * 0.9); - let gain = 1 - occlusion * 0.8; - sound._occlusionFilter.frequency.setValueAtTime(freq, Howler.ctx.currentTime); - sound._node.gain.setValueAtTime(gain * this._getEffectiveVolume(sound), Howler.ctx.currentTime); - } - } - - _updateEnvironment() { - if (!Howler._environment || !this._webAudio) return; - - if (!this._environmentReverb) { - this._environmentReverb = Howler.ctx.createConvolver(); - let { size, decay, dampening } = Howler._environment; - let length = Howler.ctx.sampleRate * (size === 'large' ? 6 : size === 'medium' ? 3 : 1.5); - let impulse = Howler.ctx.createBuffer(2, length, Howler.ctx.sampleRate); - - for (let channel = 0; channel < 2; channel++) { - let channelData = impulse.getChannelData(channel); - for (let i = 0; i < length; i++) { - let progress = i / length; - let sample = 0; - - if (i < Howler.ctx.sampleRate * 0.2) { - for (let j = 0; j < 8; j++) { - let delay = (j + 1) * 0.02 * Howler.ctx.sampleRate; - if (Math.abs(i - delay) < 100) { - sample += (Math.random() * 2 - 1) * 0.3 * Math.exp(-j * 0.5); - } - } - } - - let envelope = Math.pow(1 - progress, decay); - let reverb = (Math.random() * 2 - 1) * envelope; - sample += reverb * (1 - dampening + Math.random() * dampening * 0.3); - - if (size === 'large') { - let lowFreq = Math.sin(i * 0.01) * envelope * 0.2; - sample += lowFreq; - } - - channelData[i] = Math.tanh(sample * 0.8); - } - } - this._environmentReverb.buffer = impulse; - - this._environmentGain = Howler.ctx.createGain(); - this._environmentGain.gain.setValueAtTime(0.8, Howler.ctx.currentTime); - this._environmentReverb.connect(this._environmentGain); - this._environmentGain.connect(Howler.masterGain); - } - - this._rebuildEffectChain(); - } -} - -let Howler = new HowlerGlobal(); - -return { Howler, Howl }; - -})); diff --git a/site/info/uce-starter/js/u-macrobars-demo.html b/site/info/uce-starter/js/u-macrobars-demo.html deleted file mode 100755 index 63dc607..0000000 --- a/site/info/uce-starter/js/u-macrobars-demo.html +++ /dev/null @@ -1,977 +0,0 @@ - - - - - - U-Macrobars.js Demo - - - -
-

U-Macrobars.js Demo

- -
-
-

Basic Field Output

-
-
{{name}} is {{age}} years old and works as {{job or "unemployed"}}
-
-
- - -
-
- -
-

Number Formatting

-
Price: ${{%price}} | Large Number: {{~bigNumber}}
-
-
- - -
-
- -
-

Default Values & Safety

-
{{username or "Guest"}} | {{profile.bio or "No bio available"}}
-
-
- - -
-
-
- -
-

Field Output API

- -
-

Basic Syntax

-
{{field}}Safe HTML output
-
{{{field}}}Raw HTML output
-
{{:variable}}Direct variable
-
{{field or "default"}}With fallback
-
- -
-

Number Formatting

-
{{%number}}2 decimal places
-
{{~number}}Rounded (1k, 1M)
-
- -
-

Examples

-
-// Basic field output
-const template = Macrobars.compile('{{name}}');
-const result = template({name: 'John'});
-
-// With defaults
-const withDefault = '{{title or "Untitled"}}';
-
-// Number formatting
-const price = '${{%cost}}'; // $12.34
-const count = '{{~views}}';  // 1.2k
-
-
-
-
- -
-
-

Control Structures

-
-

Conditionals

-
{{#if isLoggedIn}} -Welcome back, {{username}}! -{{#else}} -Please log in to continue. -{{/if}}
-
-
- - -
-
- -
-

Loops & Iteration

-
{{#each items}} -• {{number}}. {{name}} - ${{price}} -{{/each}}
-
-
- - -
-
- -
-

Equality & Lookup

-
{{#eq status "active"}}User is active{{/eq}} -{{lookup user "permissions"}}
-
-
- - -
-
-
- -
-

Control Flow API

- -
-

Conditionals

-
{{#if condition}}...{{/if}}
-
{{#else}}Alternative branch
-
- Conditional rendering based on truthy values. Supports nested conditions. -
-
- -
-

Loops

-
{{#each items}}...{{/each}}
-
{{#each items as item}}...{{/each}}
-
- • Standard: data becomes current item
- • Named: item becomes current item, data preserved -
-
- -
-

Comparison & Lookup

-
{{#eq val1 val2}}...{{/eq}}
-
{{eq val1 val2}}"true" or ""
-
{{#lookup obj key}}...{{/lookup}}
-
{{lookup obj key}}value or ""
-
- -
-

Examples

-
-// Conditionals
-'{{#if user.isAdmin}}Admin Panel{{/if}}'
-
-// Named loops
-'{{#each products as product}}'
-  '{{product.name}} - {{data.storeName}}'
-'{{/each}}'
-
-// Equality & lookup
-'{{#eq user.role "admin"}}Secret{{/eq}}'
-'{{lookup config "theme"}}'
-
-
-
-
- -
-
-

Advanced Features

-
-

Event Binding

-
<button {{@click="handleClick"}}>Click Count: {{clickCount}}</button>
-
-
- - -
-
- -
-

Code Blocks

-
<script>var computed = data.value * 2;</script> -Result: {{:computed}}
-
-
- - -
-
- -
-

Components

-
{{#component userCard}}
-
-
- - -
-
-
- -
-

Advanced API

- -
-

Event Binding

-
{{@event="handler"}}DOM attribute
-
template.renderTo(container, data)
-
- Events are automatically bound when using renderTo(). Handler can reference data properties or global functions. -
-
- -
-

Code Execution

-
<script>...</script>
-
<defer>...</defer>
-
<? code ?>
-
<?= expression ?>
-
- -
-

Components & Compilation

-
Macrobars.compile(template, options)
-
Macrobars.createComponents(definitions)
-
- -
-

Examples

-
-// Event binding with renderTo
-const template = Macrobars.compile(
-  '<button {{@click="increment"}}>{{count}}</button>'
-);
-template.renderTo('#container', {
-  count: 0,
-  increment: function() { this.count++; }
-});
-
-// Components
-const components = Macrobars.createComponents({
-  userCard: '<div>{{name}} - {{email}}</div>'
-});
-
-
-
-
- -
-
-

Template Editor

-
- - - - - - - -
- - - - -
- -
Click "Render Template"
- -
-

Template Information

-
Ready.
-
- -
-
- -
-

Compilation & Debugging

- -
-

Compilation Options

-
decimals: numberNumber precision
-
strict: booleanStrict mode
-
components: objectReusable templates
-
- -
-

Debugging Properties

-
template.tokensParsed tokens
-
template.gensourceGenerated JS
-
template.event_bindingsEvent data
-
- -
-

Utility Functions

-
Macrobars.safe_out(text, default)
-
Macrobars.num_out(number, decimals)
-
Macrobars.num_out_round(number)
-
- -
-

Example Templates

-
-// Complete example
-const template = Macrobars.compile(`
-<div class="user-card">
-  <h3>{{name or "Unknown User"}}</h3>
-  {{#if profile.verified}}✅ Verified{{/if}}
-  <p>Balance: ${{%balance}}</p>
-  {{#each achievements}}
-    <span class="badge">{{data}}</span>
-  {{/each}}
-</div>
-`, { decimals: 2 });
-
-const result = template(userData);
-
-
-
-
-
- - - - - diff --git a/site/info/uce-starter/js/u-macrobars.js b/site/info/uce-starter/js/u-macrobars.js deleted file mode 100755 index b09b46d..0000000 --- a/site/info/uce-starter/js/u-macrobars.js +++ /dev/null @@ -1,411 +0,0 @@ -(function (root, factory) { // I really hate this convoluted bullshit - if (typeof exports === 'object' && typeof module !== 'undefined') { - module.exports = factory(); - } else if (typeof define === 'function' && define.amd) { - define([], factory); - } else { - root.Macrobars = factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { - - if(!String.prototype.replaceAll) String.prototype.replaceAll = function(search, replacement) { - var target = this; - return target.split(search).join(replacement); - }; - - var safe_out = (s, defaultValue = '') => { - if(typeof s == 'undefined' || s === null || s === false || s === '') s = defaultValue; - return((''+s).replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"')); - }; - - var num_out = (n, decimals = 2) => { - if(typeof n == 'undefined' || n === false) n = 0; - if(decimals == 0) return(Math.round(n)); - return(n.toFixed(decimals)); - } - - var num_out_round = (n) => { - if(typeof n == 'undefined' || n === false || n === null) n = 0; - - if(typeof n === 'string') { - n = parseFloat(n); - if(isNaN(n)) return '0'; - } - - if(Math.abs(n) >= 1e15) { - return n.toExponential(2); - } - - if(Math.abs(n) > 0 && Math.abs(n) < 0.001) { - return n.toExponential(2); - } - - if(Math.abs(n) >= 1e12) { - return (n/1e12).toFixed(1) + 'T'; - } else if(Math.abs(n) >= 1e9) { - return (n/1e9).toFixed(1) + 'B'; - } else if(Math.abs(n) >= 1e6) { - return (n/1e6).toFixed(1) + 'M'; - } else if(Math.abs(n) >= 1e3) { - return (n/1e3).toFixed(1) + 'k'; - } else if(Math.abs(n) >= 1) { - return Math.round(n); - } else if(Math.abs(n) >= 0.01) { - return n.toFixed(2); - } else if(Math.abs(n) >= 0.001) { - return n.toFixed(3); - } else if(n === 0) { - return 0; - } - - return n.toString(); - } - - var debug_out = (ee) => { - var es = ee.stack.split("\n"); - var loc = es[1]; - var p0 = loc.indexOf(''); - if(p0 != -1) { - loc = loc.substr(p0+(''.length+1)); - loc = loc.substr(0, loc.length-1); - } - return('Macrobars '+es[0]+' ('+loc+')'); - } - - var signposts = [ - { start : '', type : 'code' }, - { start : '', end : '', type : 'defer' }, - - { start : '', type : 'field' }, - { start : '', type : 'var_out' }, - { start : '', type : 'code' }, - { start : '', type : 'code' }, - - { start : '{{:', end : '}}', type : 'var_out' }, - { start : '{{#eq ', end : '}}', type : 'eq_block_start' }, - { start : '{{#lookup ', end : '}}', type : 'lookup_block_start' }, - { start : '{{eq ', end : '}}', type : 'eq_inline' }, - { start : '{{lookup ', end : '}}', type : 'lookup_inline' }, - { start : '{{#default ', end : '}}', type : 'default_empty' }, - { start : '{{#if ', end : '}}', type : 'if_start' }, - { start : '{{#else}}', end : '', type : 'else' }, - { start : '{{#component ', end : '}}', type : 'component' }, - { start : '{{#each ', end : '}}', type : 'each_start' }, - { start : '{{/each}}', end : '', type : 'each_end' }, - { start : '{{/if}}', end : '', type : 'if_end' }, - { start : '{{/eq}}', end : '', type : 'eq_block_end' }, - { start : '{{/lookup}}', end : '', type : 'lookup_block_end' }, - { start : '{{/', end : '}}', type : 'block_end' }, - { start : '{{@', end : '}}', type : 'event_bind' }, - { start : '{{{', end : '}}}', type : 'field_unsafe' }, - { start : '{{%', end : '}}', type : 'field_number' }, - { start : '{{~', end : '}}', type : 'field_number_round' }, - { start : '{{', end : '}}', type : 'field' }, - ]; - - if(!each) function each(o, f) { - if(!o) - return; - if(o.forEach) { - o.forEach(f); - } else { - for(var prop in o) if(o.hasOwnProperty(prop)) { - f(o[prop], prop); - } - } - } - - var data_prefix = (identifier) => { - if(identifier.substr(0, 1) == ':') - return(identifier.substr(1)); - else - return('data.'+identifier); - } - - var parse_field_with_default = (fieldText) => { - var orMatch = fieldText.match(/^(.+?)\s+or\s+(['"])(.*?)\2$/); - if (orMatch) { - return { - field: orMatch[1].trim(), - default: orMatch[3] - }; - } - return { - field: fieldText.trim(), - default: null - }; - } - - var compile = function(text, options = {}) { - - var crash_counter = 0; - var tokens = []; - var gensource = []; - var event_bindings = []; - var components = options.components || {}; - var condition_stack = []; - - var emit = { - text : (token) => { - gensource.push('output += '+JSON.stringify(token.text)+';'); - }, - code : (token) => { - gensource.push(token.text); - }, - defer : (token) => { - gensource.push('output += "";'); - }, - var_out : (token) => { - var defaultVal = token.default ? JSON.stringify(token.default) : 'default_empty_field'; - gensource.push('output += safe_out('+(token.text)+', '+defaultVal+');'); - }, - field : (token) => { - var defaultVal = token.default ? JSON.stringify(token.default) : 'default_empty_field'; - gensource.push('output += safe_out('+data_prefix(token.text)+', '+defaultVal+');'); - }, - field_unsafe : (token) => { - if (token.default) { - gensource.push('output += ('+data_prefix(token.text)+' || '+JSON.stringify(token.default)+');'); - } else { - gensource.push('output += ('+data_prefix(token.text)+' || default_empty_field);'); - } - }, - field_number : (token) => { - gensource.push('output += num_out('+data_prefix(token.text)+', this.decimals);'); - }, - field_number_round : (token) => { - gensource.push('output += num_out_round('+data_prefix(token.text)+');'); - }, - each_start : (token) => { - var parts = token.text.split(' as '); - var collection = parts[0].trim(); - var itemName = parts.length > 1 ? parts[1].trim() : 'data'; - - gensource.push('each('+data_prefix(collection)+', ('+itemName+', index) => {'); - - }, - if_start : (token) => { - condition_stack.push('if'); - gensource.push('if ('+data_prefix(token.text)+') {'); - }, - else : (token) => { - gensource.push('} else {'); - }, - if_end : (token) => { - condition_stack.pop(); - gensource.push('} /* if end */'); - }, - each_end : (token) => { - gensource.push('}); /* each end */'); - }, - block_end : (token) => { - var block_type = condition_stack.pop(); - gensource.push('}); /* '+(block_type || 'each')+' end */'); - }, - component : (token) => { - var comp_name = token.text.trim(); - if (components[comp_name]) { - gensource.push('output += components['+JSON.stringify(comp_name)+'](data);'); - } else { - gensource.push('output += "[Component '+comp_name+' not found]";'); - } - }, - event_bind : (token) => { - // Parse event binding: @click="functionName" or @click="data.handler" - var parts = token.text.split('='); - if (parts.length === 2) { - var event_type = parts[0].trim(); - var handler_ref = parts[1].trim().replace(/"/g, ''); - var binding_id = 'mb_bind_' + event_bindings.length; - event_bindings.push({ - id: binding_id, - event: event_type, - handler: handler_ref - }); - gensource.push('output += " data-mb-bind=\\"'+binding_id+'\\"";'); - } - }, - eq_block_start : (token) => { - // Parse "value1 value2" for equality comparison block - var parts = token.text.trim().split(/\s+/); - if (parts.length >= 2) { - var val1 = parts[0].startsWith('"') || parts[0].startsWith("'") ? parts[0] : data_prefix(parts[0]); - var val2 = parts[1].startsWith('"') || parts[1].startsWith("'") ? parts[1] : data_prefix(parts[1]); - condition_stack.push('eq'); - gensource.push('if ('+val1+' == '+val2+') {'); - } - }, - lookup_block_start : (token) => { - // Parse "object key" for dynamic property lookup block (checks if property exists and is truthy) - var parts = token.text.trim().split(/\s+/); - if (parts.length >= 2) { - var obj = data_prefix(parts[0]); - var key = parts[1].startsWith('"') || parts[1].startsWith("'") ? parts[1] : data_prefix(parts[1]); - condition_stack.push('lookup'); - gensource.push('if ('+obj+' && '+obj+'['+key+']) {'); - } - }, - eq_inline : (token) => { - // Parse "value1 value2" for equality comparison - outputs result directly - var parts = token.text.trim().split(/\s+/); - if (parts.length >= 2) { - var val1 = parts[0].startsWith('"') || parts[0].startsWith("'") ? parts[0] : data_prefix(parts[0]); - var val2 = parts[1].startsWith('"') || parts[1].startsWith("'") ? parts[1] : data_prefix(parts[1]); - var defaultVal = token.default ? JSON.stringify(token.default) : 'default_empty_field'; - gensource.push('output += safe_out(('+val1+' == '+val2+') ? "true" : "", '+defaultVal+');'); - } - }, - lookup_inline : (token) => { - // Parse "object key" for dynamic property lookup - outputs result directly - var parts = token.text.trim().split(/\s+/); - if (parts.length >= 2) { - var obj = data_prefix(parts[0]); - var key = parts[1].startsWith('"') || parts[1].startsWith("'") ? parts[1] : data_prefix(parts[1]); - var defaultVal = token.default ? JSON.stringify(token.default) : 'default_empty_field'; - gensource.push('output += safe_out(('+obj+' && '+obj+'['+key+']) || "", '+defaultVal+');'); - } - }, - eq_block_end : (token) => { - condition_stack.pop(); - gensource.push('} /* eq end */'); - }, - lookup_block_end : (token) => { - condition_stack.pop(); - gensource.push('} /* lookup end */'); - }, - default_empty : (token) => { - gensource.push('default_empty_field = '+JSON.stringify(token.text)+';'); - }, - } - - while(text != '' && crash_counter < 100) { - - crash_counter+=1; - var p0 = -1; - var sp_found = false; - signposts.forEach((sp) => { - var ps = text.indexOf(sp.start); - if(ps != -1 && (p0 == -1 || p0 > ps)) { - sp_found = sp; - p0 = ps; - } - }); - - if(sp_found) - { - tokens.push({ type : 'text', text : text.substr(0, p0) }); - text = text.substr(p0 + sp_found.start.length); - var p1 = text.indexOf(sp_found.end); - if(p1 == -1) p1 = text.length; - - var tokenText = text.substr(0, p1); - var token = { type : sp_found.type, text : tokenText }; - - if (sp_found.type === 'field' || sp_found.type === 'var_out' || - sp_found.type === 'field_unsafe' || sp_found.type === 'field_number' || - sp_found.type === 'field_number_round') { - var parsed = parse_field_with_default(tokenText); - token.text = parsed.field; - token.default = parsed.default; - } - - tokens.push(token); - text = text.substr(p1+sp_found.end.length); - } - else - { - tokens.push({ type : 'text', text : text }); - text = ''; - } - - } - - if(typeof options.decimals == 'undefined') - options.decimals = 2; - this.decimals = options.decimals; - - gensource.push('(data) => { '); - if(options.strict) - gensource.push('"use strict";'); - gensource.push(' try {'); - gensource.push(' if(!data) data = {}; var data_root = data;'); - gensource.push(' var output = ""; var default_empty_field = "";'); - gensource.push(' var echo = (s) => { output += s; };'); - tokens.forEach((tok) => { - emit[tok.type](tok); - }); - gensource.push(' } catch (ee) { console.error(ee); output += debug_out(ee); }'); - gensource.push(' return(output);'); - gensource.push('}'); - - var f = {}; - try { - f = eval('('+gensource.join("\n")+')'); - } catch(ce) { - console.error('Macrobars compilation error:', ce); - console.error('Template source:', text.substring(0, 200) + (text.length > 200 ? '...' : '')); - console.error('Generated JavaScript:', gensource.join("\n")); - } - - f.tokens = tokens; - f.gensource = gensource; - f.event_bindings = event_bindings; - f.options = options; - f.components = components; - - f.renderTo = function(container_or_query, data) { - var container; - if (typeof container_or_query === 'string') { - container = document.querySelector(container_or_query); - if (!container) { - return null; - } - } else { - container = container_or_query; - } - - try { - var html = f(data); - container.innerHTML = html; - event_bindings.forEach(binding => { - var elements = container.querySelectorAll('[data-mb-bind="' + binding.id + '"]'); - elements.forEach(element => { - var handler = data[binding.handler] || eval(binding.handler); - if (typeof handler === 'function') { - element.addEventListener(binding.event, handler); - } - }); - }); - } catch(renderError) { - console.error('Macrobars renderTo error:', renderError); - console.error('Data passed to template:', data); - throw renderError; - } - - return container; - }; - - return(f); - } - - return({ - - compile : compile, - - createComponents : function(definitions) { - var components = {}; - each(definitions, (template, name) => { - components[name] = compile(template); - }); - return components; - }, - - num_out : num_out, - safe_out : safe_out, - num_out_round : num_out_round, - debug_out : debug_out, - each : each, - - }); - -})); diff --git a/site/info/uce-starter/js/u-macrobars.md b/site/info/uce-starter/js/u-macrobars.md deleted file mode 100755 index 191aedb..0000000 --- a/site/info/uce-starter/js/u-macrobars.md +++ /dev/null @@ -1,137 +0,0 @@ -# macrobars.js - -A lightweight JavaScript templating engine with PHP-style syntax and Handlebars-inspired features. - -## Basic Usage - -```javascript -const template = Macrobars.compile('

{{title}}

{{content}}

'); -const html = template({title: 'Hello', content: 'World'}); -``` - -## Field Output - -```javascript -{{field}} // Safe HTML output (escaped) -{{{field}}} // Unsafe HTML output (raw) -{{field or "default"}} // With default value -{{:variable}} // Direct variable (no data. prefix) -``` - -## Numbers - -```javascript -{{%number}} // Formatted number (2 decimals) -{{~number}} // Rounded number (1k, 1M format) -``` - -## Control Structures - -### Conditionals -```javascript -{{#if condition}} - Content when true -{{#else}} - Content when false -{{/if}} -``` - -### Equality Blocks -```javascript -{{#eq value1 value2}} - Content when equal -{{/eq}} - -{{eq value1 value2}} // Inline: outputs "true" or "" -``` - -### Loops -```javascript -{{#each items}} - {{name}} - {{index}} -{{/each}} - -{{#each items as item}} - {{item.name}} -{{/each}} -``` - -### Property Lookup -```javascript -{{#lookup object key}} - {{value}} exists -{{/lookup}} - -{{lookup object key}} // Inline: outputs value or "" -``` - -## Code Blocks - -```javascript - - - - // Deferred JavaScript execution - - - // PHP-style output - // PHP-style code -``` - -## Event Binding - -```javascript - -``` - -Events are automatically bound when using `renderTo()`. - -## Components - -```javascript -{{#component myComponent}} // Render registered component -``` - -## Compilation Options - -```javascript -const template = Macrobars.compile(templateString, { - decimals: 2, // Number formatting precision - strict: true, // Use strict mode - components: {...} // Reusable components -}); -``` - -## DOM Integration - -```javascript -template.renderTo('#container', data); // Render to element -template.renderTo(document.getElementById('x'), data); -``` - -## Utility Functions - -```javascript -Macrobars.safe_out(text, default) // HTML escape -Macrobars.num_out(number, decimals) // Format number -Macrobars.num_out_round(number) // Round with k/M suffix -``` - -## Template Debugging - -Access compiled template information: -```javascript -template.tokens // Parsed tokens -template.gensource // Generated JavaScript -template.event_bindings // Event binding data -``` - -## Default Values - -```javascript -{{#default "N/A"}} // Set default for empty fields -{{field}} // Will show "N/A" if empty -``` - diff --git a/site/info/uce-starter/js/u-popup-menu.css b/site/info/uce-starter/js/u-popup-menu.css deleted file mode 100644 index fb30ca3..0000000 --- a/site/info/uce-starter/js/u-popup-menu.css +++ /dev/null @@ -1,34 +0,0 @@ -:root { - --vp-size-popup-min-width: 160px; -} - -.vp-popup-menu { - position: absolute; - background: var(--vp-color-black); - border: 1px solid var(--color-border); - color: var(--vp-color-white); - min-width: var(--vp-size-popup-min-width); - z-index: var(--vp-z-popup); - border-radius: var(--vp-space-l); - overflow: hidden; -} - -.vp-popup-item { - padding: var(--vp-space-l); - cursor: pointer; - white-space: nowrap; -} - -.vp-popup-item:hover { - color: var(--color-highlight); -} - -.vp-popup-item.focused { - background: var(--color-highlight); - color: var(--vp-color-black); -} - -.vp-popup-empty { - padding: var(--vp-space-l); - color: var(--vp-color-gray); -} \ No newline at end of file diff --git a/site/info/uce-starter/js/u-popup-menu.js b/site/info/uce-starter/js/u-popup-menu.js deleted file mode 100644 index e30498b..0000000 --- a/site/info/uce-starter/js/u-popup-menu.js +++ /dev/null @@ -1,84 +0,0 @@ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - // AMD - define(['jquery'], factory); - } else if (typeof module === 'object' && module.exports) { - // CommonJS - module.exports = factory(require('jquery')); - } else { - // Browser globals - root.showPopupMenu = factory(root.$); - } -}(typeof self !== 'undefined' ? self : this, function ($) { - 'use strict'; - - let showPopupMenu = (x, y, items, prop = {}) => { - document.querySelectorAll('.vp-popup-menu').forEach(menu => { - if(menu.parentNode) menu.parentNode.removeChild(menu); - }); - - let container = prop.container || document.body; - let menu = $('
').css({ - position: 'absolute', - left: (x|0) + 'px', - top: (y|0) + 'px' - })[0]; - - let elems = []; - if(!items || !items.length) { - $(menu).append(`
${prop.emptyText || 'No items'}
`); - } else { - items.forEach((it, idx) => { - let label = typeof it === 'string' ? it : (it.label || it.screen || it.name || JSON.stringify(it)); - let $item = $(`
${label}
`) - .attr('data-idx', idx) - .on('click', ev => { ev.stopPropagation(); try { (prop.onSelect || (()=>{}))(it); } catch(e){ console.error(e); } removeMenu(); }) - .on('keydown', e => { if(e.key === 'Enter') { e.preventDefault(); $item[0].click(); } }); - $(menu).append($item[0]); - elems.push({el: $item[0], data: it}); - }); - } - - let focusedIndex = elems.length ? 0 : -1; - let focusAt = i => { - elems.forEach((it, idx) => { $(it.el).removeClass('focused'); if(idx === i) { $(it.el).addClass('focused'); try{ it.el.focus(); }catch(e){} } }); - focusedIndex = i; - }; - - let removeMenu = () => { - if(menu.parentNode) menu.parentNode.removeChild(menu); - $(document).off('mousedown', onDoc).off('keydown', onKey); - $(window).off('resize', onResize); - }; - let onDoc = ev => { if(!menu.contains(ev.target)) removeMenu(); }; - let onResize = () => reposition(); - let onKey = ev => { - if(!elems.length) { if(ev.key === 'Escape') removeMenu(); return; } - if(ev.key === 'Escape') { ev.preventDefault(); removeMenu(); return; } - if(ev.key === 'ArrowDown') { ev.preventDefault(); focusAt((focusedIndex + 1) % elems.length); return; } - if(ev.key === 'ArrowUp') { ev.preventDefault(); focusAt((focusedIndex - 1 + elems.length) % elems.length); return; } - if(ev.key === 'Home') { ev.preventDefault(); focusAt(0); return; } - if(ev.key === 'End') { ev.preventDefault(); focusAt(elems.length - 1); return; } - if(ev.key === 'Enter') { ev.preventDefault(); if(focusedIndex >= 0) elems[focusedIndex].el.click(); } - }; - - container.appendChild(menu); - let reposition = () => { - let mRect = menu.getBoundingClientRect(); - let winW = window.innerWidth, winH = window.innerHeight; - let left = parseInt($(menu).css('left'),10) || 0, top = parseInt($(menu).css('top'),10) || 0; - if(mRect.right > winW) left = Math.max(4, winW - Math.ceil(mRect.width) - 8); - if(mRect.bottom > winH) top = Math.max(4, winH - Math.ceil(mRect.height) - 8); - if(left < 4) left = 4; if(top < 4) top = 4; - $(menu).css({left: left + 'px', top: top + 'px'}); - }; - - $(document).on('mousedown', onDoc).on('keydown', onKey); - $(window).on('resize', onResize); - if(elems.length) { focusAt(0); } - setTimeout(reposition, 0); - return menu; - }; - - return showPopupMenu; -})); \ No newline at end of file diff --git a/site/info/uce-starter/js/u-query-demo.html b/site/info/uce-starter/js/u-query-demo.html deleted file mode 100755 index ce48d39..0000000 --- a/site/info/uce-starter/js/u-query-demo.html +++ /dev/null @@ -1,976 +0,0 @@ - - - - - - U-Query.js Demo - - - -
-

U-Query.js Demo

- -
-
-

Element Selection & DOM Manipulation

-
-

DOM Queries

-
- Select elements to see them highlighted -
-
Test Element 1
-
Test Element 2
-
Test Element 3 (special)
- -
- - - - -
- -
-
- -
-

DOM Manipulation

-
Original content
- -
- - - - -
- -
-
- -
-

CSS & Classes

-
CSS Target Element
- -
- - - - -
- -
-
-
- -
-

Selection API

- -
-

Core Selectors

-
$(selector) → NodeList
-
$('.class') → NodeList
-
$('#id') → NodeList
-
$('tag') → NodeList
-
- -
-

DOM Manipulation

-
html(content?) → NodeList|string
-
text(content?) → NodeList|string
-
append(content) → NodeList
-
prepend(content) → NodeList
-
remove() → NodeList
-
- -
-

CSS & Classes

-
css(styles) → NodeList
-
addClass(className) → NodeList
-
removeClass(className) → NodeList
-
toggleClass(className) → NodeList
-
- -
-

Examples

-
-// Element selection
-const elements = $('.my-class');
-const byId = $('#my-id');
-
-$('.target').html('<b>New content</b>');
-$('.target').text('Plain text');
-$('.container').append('<p>Added</p>');
-
-$('.element').css({
-  'color': 'red',
-  'background': 'blue'
-});
-$('.element').addClass('active');
-
-
-
-
- -
-
-

Event Handling & Visibility

-
-

Event System

- - -
- - - -
- -
-
- -
-

Show/Hide/Toggle

-
Toggle me!
- -
- - - - -
- -
-
- -
-

Method Chaining

-
-
Chain Target 1
-
Chain Target 2
-
Chain Target 3
-
- -
- - -
- -
-
-
- -
-

Events & Visibility API

- -
-

Event Methods

-
on(event, handler) → NodeList
-
off(event, handler?) → NodeList
-
trigger(event, data?) → NodeList
-
once(event, handler) → NodeList
-
- -
-

Visibility Control

-
show() → NodeList
-
hide() → NodeList
-
toggle() → NodeList
-
fadeIn(duration?) → NodeList
-
fadeOut(duration?) → NodeList
-
- -
-

Method Chaining

-
- All u-query methods return the NodeList, enabling method chaining. -
-
-$('.button').on('click', function() {
-  console.log('Clicked!');
-});
-
-$('.element')
-  .addClass('active')
-  .css({'color': 'red'})
-  .show()
-  .on('click', handler);
-
-$('.modal').fadeIn(300);
-$('.tooltip').fadeOut(200);
-
-
-
-
- -
-
-

AJAX & Global Events

-
-

AJAX Utilities

-
-
- AJAX Request Status -
- -
- - - -
- -
-
- -
-

Global Event System

- - -
- - - -
- -
-
- -
-

Utility Functions

-
Utility Element 1
-
Utility Element 2
-
Utility Element 3
- -
- - - -
- -
-
-
- -
-

AJAX & Utilities API

- -
-

AJAX Methods

-
$.get(url, callback) → Promise
-
$.post(url, data, callback) → Promise
-
$.ajax(options) → Promise
-
$.json(url) → Promise
-
- -
-

Global Event System

-
$.on(event, handler) → $
-
$.off(event, handler?) → $
-
$.emit(event, data?) → number
-
$.trigger(event, data?) → number
-
- -
-

Utility Functions

-
$.each(selector, callback) → $
-
$.ready(callback) → $
-
$.extend(target, ...sources) → object
-
$.map(selector, callback) → Array
-
- -
-

Examples

-
-const data = await $.get('/api/users');
-$.post('/api/users', {name: 'John'})
-  .then(response => console.log(response));
-
-$.on('user-login', user => {
-  console.log('User logged in:', user);
-});
-$.emit('user-login', {id: 123});
-
-$.each('.item', (el, i) => {
-  el.textContent = `Item ${i}`;
-});
-
-$.ready(() => {
-  console.log('DOM ready!');
-});
-
-
-
-
- -
-
-

Browser Info

-
-
Loading library information...
- -

This browser supports

-
- -
- - -
-
-
- -
-

Advanced Features

- -
-

Advanced Selectors

-
$(':visible') → NodeList
-
$(':hidden') → NodeList
-
$(':checked') → NodeList
-
$(':first') → NodeList
-
$(':last') → NodeList
-
- -
-

Data Attributes

-
data(key, value?) → NodeList|any
-
attr(name, value?) → NodeList|string
-
prop(name, value?) → NodeList|any
-
val(value?) → NodeList|string
-
- -
-

Traversal Methods

-
parent() → NodeList
-
children() → NodeList
-
siblings() → NodeList
-
find(selector) → NodeList
-
closest(selector) → NodeList
-
- -
-

DOM Diff Updates

-
- u-query can make use of morphdom.js for efficient DOM diff updates. -
-
$.options.alwaysDoDifferentialUpdate = true
-
- Global flag for morphdom. -
-
- -
-
-
- - - - - diff --git a/site/info/uce-starter/js/u-query.js b/site/info/uce-starter/js/u-query.js deleted file mode 100755 index 907e8ba..0000000 --- a/site/info/uce-starter/js/u-query.js +++ /dev/null @@ -1,589 +0,0 @@ -(function (root, factory) { - // this is the stupid UMD pattern, but eh we lost that battle a long time ago - if (typeof exports === 'object' && typeof module !== 'undefined') { - var exports_obj = factory(); - module.exports = exports_obj.$; - // Also export individual components - for (var key in exports_obj) { - if (key !== '$' && exports_obj.hasOwnProperty(key)) { - exports[key] = exports_obj[key]; - } - } - } else if (typeof define === 'function' && define.amd) { - define([], factory); - } else { - var exports_obj = factory(); - root.$ = exports_obj.$; - for (var key in exports_obj) { - if (key !== '$' && exports_obj.hasOwnProperty(key)) { - root[key] = exports_obj[key]; - } - } - } -}(typeof self !== 'undefined' ? self : this, function () { - -// a collection of DOM utility functions that I thought were cool in jQuery - -class EventEmitter { - constructor() { - /** Map> */ - this._topics = new Map(); - } - - /** - * Subscribe to `topic`. If `slot_key` is provided (truthy), - * it dedupes by that key; otherwise a unique Symbol is used. - * Returns an unsubscribe fn. - */ - on(topic, handler, slot_key = null) { - let map = this._topics.get(topic); - if (!map) { - map = new Map(); - this._topics.set(topic, map); - } - // use the provided slot_key or a fresh Symbol() - const key = slot_key != null ? slot_key : Symbol(); - map.set(key, handler); - return () => this.off(topic, key); - } - - /** - * Unsubscribe by handler function or by slot_key. - */ - off(topic, handlerOrSlotKey) { - const map = this._topics.get(topic); - if (!map) return; - - // if it matches a slotKey directly, remove it - if (map.has(handlerOrSlotKey)) { - map.delete(handlerOrSlotKey); - } else { - // otherwise assume it's a function: remove all matching fns - for (const [key, fn] of map.entries()) { - if (fn === handlerOrSlotKey) { - map.delete(key); - } - } - } - - if (map.size === 0) { - this._topics.delete(topic); - } - } - - /** - * Emit to all handlers on `topic`. Handlers returning - * 'remove_handler' are auto-removed. - * Returns the number of handlers invoked. - */ - emit(topic, ...args) { - let count = 0; - const map = this._topics.get(topic); - if (!map) return count; - - for (const [key, fn] of Array.from(map.entries())) { - const res = fn(...args); - count++; - if (res === 'remove_handler') { - map.delete(key); - } - } - - if (map.size === 0) { - this._topics.delete(topic); - } - return count; - } -} - -class QueryWrapper extends Array { - constructor(elements) { - super(); - if (elements) { - this.push(...(Array.isArray(elements) ? elements : [elements])); - } - } -} - -$ = function(selector_or_element) { - let elements; - if (selector_or_element instanceof Element || selector_or_element === document || selector_or_element === window) { - elements = [selector_or_element]; - } else if (typeof selector_or_element === 'string') { - // Check if string looks like HTML (starts with < and ends with >) - if (selector_or_element.trim().charAt(0) === '<' && selector_or_element.trim().charAt(selector_or_element.trim().length - 1) === '>') { - // Create element from HTML string - let temp = document.createElement('div'); - temp.innerHTML = selector_or_element.trim(); - elements = Array.from(temp.children); - } else { - // Treat as CSS selector - elements = Array.from(document.querySelectorAll(selector_or_element)); - } - } else if (selector_or_element instanceof NodeList || Array.isArray(selector_or_element)) { - elements = Array.from(selector_or_element); - } else { - elements = [selector_or_element]; - } - return new QueryWrapper(elements); -}; - -$.options = { - alwaysDoDifferentialUpdate: true, -}; - -$.events = new EventEmitter(); -$.on = $.events.on.bind($.events); -$.off = $.events.off.bind($.events); -$.emit = $.events.emit.bind($.events); - -$.each = function(selector, callback) { - let elements; - if (typeof selector === 'string') { - elements = document.querySelectorAll(selector); - } else if (selector instanceof QueryWrapper) { - elements = selector; - } else { - elements = selector; - } - for (let i = 0; i < elements.length; i++) { - callback(elements[i], i); - } -} - -$.post = function(url, data, callback) { - return $.ajax({ - method: 'POST', - url: url, - data: data, - success: callback, - error: function(xhr) { - console.error('POST request failed:', xhr); - } - }); -} - -$.get = function(url, callback) { - return $.ajax({ - method: 'GET', - url: url, - success: callback, - error: function(xhr) { - console.error('GET request failed:', xhr); - } - }); -} - -$.ajax = function(options) { - return new Promise((resolve, reject) => { - var xhr = new XMLHttpRequest(); - xhr.open(options.method || 'GET', options.url, true); - - // Set default headers - if (options.method === 'POST' || options.data) { - xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); - } - - // Set custom headers - if (options.headers) { - for (var key in options.headers) { - xhr.setRequestHeader(key, options.headers[key]); - } - } - - xhr.onreadystatechange = function() { - if (xhr.readyState === 4) { - var response; - try { - response = JSON.parse(xhr.responseText); - } catch (e) { - // If JSON parsing fails, use raw response - response = xhr.responseText; - } - - if (xhr.status >= 200 && xhr.status < 300) { - if (options.success) options.success(response); - resolve(response); - } else { - if (options.error) options.error(xhr); - reject(xhr); - } - } - }; - - var data = null; - if (options.data) { - data = typeof options.data === 'string' ? options.data : JSON.stringify(options.data); - } - - xhr.send(data); - }); -} - -$.ready = function(callback) { - if (document.readyState !== 'loading') { - callback(); - } else { - document.addEventListener('DOMContentLoaded', callback); - } -} - -// Helper function to execute scripts in HTML content -function executeScripts(htmlContent) { - // Create a temporary container to parse the HTML - const tempDiv = document.createElement('div'); - tempDiv.innerHTML = htmlContent; - - // Find all script tags and disable them temporarily - const scripts = tempDiv.querySelectorAll('script'); - const scriptData = []; - - scripts.forEach((script) => { - // Store script data for later execution - scriptData.push({ - content: script.textContent || script.innerText || '', - src: script.src, - type: script.type, - nonce: script.nonce, - async: script.async, - defer: script.defer - }); - - // Disable the script by changing its type - script.type = 'text/disabled-script'; - }); - - // Return the modified HTML and script data - return { - html: tempDiv.innerHTML, - scripts: scriptData - }; -} - -// Helper function to execute a single script -function executeScript(scriptInfo) { - if (scriptInfo.src) { - // External script - const newScript = document.createElement('script'); - if (scriptInfo.type && scriptInfo.type !== 'text/disabled-script') { - newScript.type = scriptInfo.type; - } - if (scriptInfo.nonce) newScript.nonce = scriptInfo.nonce; - if (scriptInfo.async) newScript.async = scriptInfo.async; - if (scriptInfo.defer) newScript.defer = scriptInfo.defer; - newScript.src = scriptInfo.src; - - document.head.appendChild(newScript); - } else if (scriptInfo.content.trim()) { - // Inline script - const newScript = document.createElement('script'); - if (scriptInfo.type && scriptInfo.type !== 'text/disabled-script') { - newScript.type = scriptInfo.type; - } - if (scriptInfo.nonce) newScript.nonce = scriptInfo.nonce; - newScript.text = scriptInfo.content; - - // Execute by inserting and immediately removing - document.head.appendChild(newScript); - document.head.removeChild(newScript); - } -} - -// Add all the jQuery-like methods to QueryWrapper -QueryWrapper.prototype.parent = function() { - const parents = Array.from(this).map(el => el.parentNode).filter(el => el); - return new QueryWrapper(parents); -} - -QueryWrapper.prototype.load = function(url, opt = {}) { - return new Promise((resolve, reject) => { - const ajaxOptions = { - method: opt.method || (opt.postData ? 'POST' : 'GET'), - url: url, - success: (response) => { - if(opt.replace) - this.replaceWith(response, opt); - else - this.html(response, opt); - if (opt.onLoad) opt.onLoad(response, null); - resolve(this); - }, - error: (xhr) => { - if (opt.onError) opt.onError(xhr); - reject(new Error('Failed to load: ' + url)); - } - }; - - if (opt.postData) { - ajaxOptions.data = opt.postData; - } - - $.ajax(ajaxOptions); - }); -} - -QueryWrapper.prototype.html = function(opt_content = false, prop = {}) { - if (opt_content === false) { - return Array.from(this).map(el => el.innerHTML).join(''); - } - if(typeof prop.diff == 'undefined') - prop.diff = $.options.alwaysDoDifferentialUpdate; - if(prop.diff === true) { - const temp = document.createElement('div'); - temp.innerHTML = opt_content; - this.forEach(el => { - morphdom(el, temp, { childrenOnly: true }); - }); - } else { - this.forEach(el => { - const result = executeScripts(opt_content); - el.innerHTML = result.html; - result.scripts.forEach(executeScript); - }); - } - return this; -} - -QueryWrapper.prototype.text = function(opt_content = false) { - if (opt_content === false) { - return Array.from(this).map(el => el.textContent).join(''); - } - this.forEach(el => { - el.textContent = opt_content; - }); - return this; -} - -QueryWrapper.prototype.replaceWith = function(content, prop = {}) { - if(typeof prop.diff == 'undefined') - prop.diff = $.options.alwaysDoDifferentialUpdate; - if(prop.diff === true) { - this.forEach(el => { - morphdom(el, content); - }); - } else { - if(typeof content === 'string') { - this.forEach(el => { - const tempDiv = document.createElement('div'); - tempDiv.innerHTML = content; - el.parentNode.replaceChild(tempDiv.firstChild, el); - }); - } else if(content instanceof Element) { - this.forEach(el => { - el.parentNode.replaceChild(content.cloneNode(true), el); - }); - } - } - return this; -} - -QueryWrapper.prototype.query = function(selector) { - const found = Array.from(this).reduce((acc, el) => { - const results = el.querySelectorAll(selector); - return acc.concat(Array.from(results)); - }, []); - return new QueryWrapper(found); -} - -QueryWrapper.prototype.find = function(selector) { - const found = Array.from(this).reduce((acc, el) => { - const results = el.querySelectorAll(selector); - return acc.concat(Array.from(results)); - }, []); - return new QueryWrapper(found); -} - -QueryWrapper.prototype.on = function(event, handler) { - this.forEach(function(el) { - el.addEventListener(event, handler); - }); - return this; -} - -QueryWrapper.prototype.off = function(event, handler) { - this.forEach(function(el) { - el.removeEventListener(event, handler); - }); - return this; -} - -QueryWrapper.prototype.hide = function() { - return this.css({ display: 'none' }); -} - -QueryWrapper.prototype.show = function() { - return this.css({ display: '' }); -} - -QueryWrapper.prototype.toggle = function() { - this.forEach(function(el) { - el.style.display = (el.style.display === 'none' || el.style.display === '') ? '' : 'none'; - }); - return this; -} - -QueryWrapper.prototype.attr = function(name, value) { - if (value === undefined) { - return this.length > 0 ? this[0].getAttribute(name) : null; - } - this.forEach(function(el) { - el.setAttribute(name, value); - }); - return this; -} - -QueryWrapper.prototype.addClass = function(classNameOrList) { - var classList = Array.isArray(classNameOrList) ? classNameOrList : [classNameOrList]; - this.forEach(function(el) { - classList.forEach(function(classNames) { - // Split space-separated class names - var classes = classNames.toString().split(/\s+/).filter(function(name) { return name.length > 0; }); - classes.forEach(function(className) { - el.classList.add(className); - }); - }); - }); - return this; -} - -QueryWrapper.prototype.removeClass = function(classNameOrList) { - var classList = Array.isArray(classNameOrList) ? classNameOrList : [classNameOrList]; - this.forEach(function(el) { - classList.forEach(function(classNames) { - // Split space-separated class names - var classes = classNames.toString().split(/\s+/).filter(function(name) { return name.length > 0; }); - classes.forEach(function(className) { - el.classList.remove(className); - }); - }); - }); - return this; -} - -QueryWrapper.prototype.toggleClass = function(classNameOrList, force) { - var classList = Array.isArray(classNameOrList) ? classNameOrList : [classNameOrList]; - this.forEach(function(el) { - classList.forEach(function(classNames) { - // Split space-separated class names - var classes = classNames.toString().split(/\s+/).filter(function(name) { return name.length > 0; }); - classes.forEach(function(className) { - if (typeof force !== 'undefined') { - el.classList.toggle(className, force); - } else { - el.classList.toggle(className); - } - }); - }); - }); - return this; -} - -QueryWrapper.prototype.empty = function() { - this.forEach(function(el) { - el.innerHTML = ''; - }); - return this; -} - -QueryWrapper.prototype.css = function(styles, optOrValue) { - // If no arguments or first argument is a string (getter mode) - if (arguments.length === 0 || (typeof styles === 'string' && arguments.length === 1)) { - if (this.length === 0) return undefined; - var el = this[0]; - if (typeof styles === 'string') { - // Get computed style for a specific property - return window.getComputedStyle(el)[styles]; - } else { - // Return computed styles object (not commonly used) - return window.getComputedStyle(el); - } - } - - // Setter mode - this.forEach(function(el) { - if (typeof styles === 'string' && arguments.length >= 2) { - // Single property setter: .css('prop', 'value') - el.style[styles] = optOrValue; - } else if (typeof styles === 'object') { - // Multiple properties setter: .css({prop1: 'value1', prop2: 'value2'}) - for (var key in styles) { - el.style[key] = styles[key]; - } - } - }); - return this; -} - -QueryWrapper.prototype.each = function(callback) { - this.forEach(function(el, index) { - callback(el, index); - }); - return this; -} - -QueryWrapper.prototype.append = function(child_or_html) { - this.forEach(function(el) { - if (typeof child_or_html === 'string' && el.insertAdjacentHTML) { - if (child_or_html.includes(' max) return max; - return v; -} - -function pick_entry_from_range(array, value) { - if (!array) return {}; - let result = {}; - for (const [pv] of Object.entries(array)) { - if (value >= pv.from && value <= pv.to) result = pv; - } - return result; -} - -return { - $: $, - EventEmitter: EventEmitter, - QueryWrapper: QueryWrapper, - first: first, - clamp: clamp, - pick_entry_from_range: pick_entry_from_range -}; - -})); \ No newline at end of file diff --git a/site/info/uce-starter/js/u-sortable-table.js b/site/info/uce-starter/js/u-sortable-table.js deleted file mode 100644 index e9fee4f..0000000 --- a/site/info/uce-starter/js/u-sortable-table.js +++ /dev/null @@ -1,168 +0,0 @@ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof module === 'object' && module.exports) { - module.exports = factory(); - } else { - root.USortableTable = factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { - 'use strict'; - const globalScope = typeof globalThis !== 'undefined' ? globalThis : (typeof window !== 'undefined' ? window : this); - - function getTable(target) { - if (!target) return null; - if (typeof target === 'string') return document.getElementById(target); - return target.nodeType === 1 ? target : null; - } - - function getStorageKey(table, options) { - if (options && options.storageKey) return options.storageKey; - if (table && table.id) return `u-sortable-table.${table.id}`; - return null; - } - - function loadSort(table, options) { - const storageKey = getStorageKey(table, options); - if (!storageKey || !globalScope.localStorage) return null; - try { - const raw = globalScope.localStorage.getItem(storageKey); - if (!raw) return null; - const parsed = JSON.parse(raw); - if (!parsed || !Number.isInteger(parsed.column) || (parsed.direction !== 'asc' && parsed.direction !== 'desc')) { - return null; - } - return parsed; - } catch (error) { - return null; - } - } - - function saveSort(table, column, direction, options) { - const storageKey = getStorageKey(table, options); - if (!storageKey || !globalScope.localStorage) return; - try { - globalScope.localStorage.setItem(storageKey, JSON.stringify({ column, direction })); - } catch (error) { - // Ignore storage errors. - } - } - - function parseSortValue(text) { - const normalized = String(text || '').trim(); - if (!normalized) return { type: 'text', value: '' }; - - if (globalScope.UFormat && typeof globalScope.UFormat.parseUnitNumber === 'function') { - const unitValue = globalScope.UFormat.parseUnitNumber(normalized); - if (unitValue != null) { - return { type: 'number', value: unitValue }; - } - } - - const timestamp = Date.parse(normalized); - if (!Number.isNaN(timestamp)) { - return { type: 'number', value: timestamp }; - } - - return { type: 'text', value: normalized.toLowerCase() }; - } - - function setHeaderState(table, columnIndex, direction) { - Array.from(table.querySelectorAll('thead th')).forEach((header, index) => { - header.classList.remove('sorted-asc', 'sorted-desc'); - header.setAttribute('aria-sort', 'none'); - if (index === columnIndex) { - header.classList.add(direction === 'asc' ? 'sorted-asc' : 'sorted-desc'); - header.setAttribute('aria-sort', direction === 'asc' ? 'ascending' : 'descending'); - } - }); - } - - function sortTable(table, columnIndex, direction, options, persist) { - const tbody = table.querySelector('tbody'); - if (!tbody) return; - - const rows = Array.from(tbody.querySelectorAll('tr')).filter((row) => row.children.length > 0 && !row.hasAttribute('data-empty-row')); - if (!rows.length) return; - - rows.sort((rowA, rowB) => { - const cellA = rowA.children[columnIndex]; - const cellB = rowB.children[columnIndex]; - const rawA = cellA ? (cellA.getAttribute('data-sort-value') || cellA.textContent) : ''; - const rawB = cellB ? (cellB.getAttribute('data-sort-value') || cellB.textContent) : ''; - const valueA = parseSortValue(rawA); - const valueB = parseSortValue(rawB); - - let comparison = 0; - if (valueA.type === 'number' && valueB.type === 'number') { - comparison = valueA.value - valueB.value; - } else { - comparison = String(valueA.value).localeCompare(String(valueB.value), undefined, { - numeric: true, - sensitivity: 'base', - }); - } - return direction === 'asc' ? comparison : -comparison; - }); - - rows.forEach((row) => tbody.appendChild(row)); - setHeaderState(table, columnIndex, direction); - if (persist !== false) { - saveSort(table, columnIndex, direction, options); - } - } - - function getInitialSort(table, options) { - const saved = loadSort(table, options); - if (saved) return saved; - if (options && options.initialSort) { - return { - column: Number(options.initialSort.column || 0), - direction: options.initialSort.direction === 'desc' ? 'desc' : 'asc', - }; - } - return null; - } - - function attachHeader(header, table, columnIndex, options) { - if (header.getAttribute('data-sortable') === 'false') return; - header.classList.add('sortable'); - header.tabIndex = 0; - header.addEventListener('click', function () { - const current = loadSort(table, options); - const nextDirection = current && current.column === columnIndex && current.direction === 'asc' ? 'desc' : 'asc'; - sortTable(table, columnIndex, nextDirection, options, true); - }); - header.addEventListener('keydown', function (event) { - if (event.key !== 'Enter' && event.key !== ' ') return; - event.preventDefault(); - header.click(); - }); - } - - function init(target, options = {}) { - const table = getTable(target); - if (!table || table.dataset.sortableTableInit === '1') return table; - - Array.from(table.querySelectorAll('thead th')).forEach((header, index) => attachHeader(header, table, index, options)); - table.dataset.sortableTableInit = '1'; - - const initialSort = getInitialSort(table, options); - if (initialSort) { - sortTable(table, initialSort.column, initialSort.direction, options, false); - } - - return table; - } - - function initAll(selector = '.u-sortable-table') { - Array.from(document.querySelectorAll(selector)).forEach((table) => init(table)); - } - - return { - init, - initAll, - parseSortValue, - sortTable, - }; -})); \ No newline at end of file diff --git a/site/info/uce-starter/js/u-tiling-viewport.css b/site/info/uce-starter/js/u-tiling-viewport.css deleted file mode 100644 index 63976c7..0000000 --- a/site/info/uce-starter/js/u-tiling-viewport.css +++ /dev/null @@ -1,165 +0,0 @@ -:root { - --vp-color-primary: rgba(255, 125, 55, 1); - --vp-color-primary-focus: rgba(255, 120, 60, 0.4); - --vp-background: rgba(0,0,0,0.2); - - --vp-color-black: #000; - --vp-color-gray: #666; - --vp-color-white: #fff; - --vp-space-s: 4px; - --vp-space-l: 6px; - - --vp-size-icon: 12px; - --vp-size-nav-height: 48px; - - --vp-opacity: 0.4; - --vp-opacity-active: 0.9; - - --vp-z-pane: 2; - --vp-z-toolbar: 3; - --vp-z-popup: 9999; - --vp-duration: 0.25s; - --vp-easing: ease; -} - -#fabric { - position: absolute; - top: var(--vp-size-nav-height); - left: 0; right: 0; bottom: 0; - display: flex; - overflow: hidden; -} - -.vp-split { - flex: 1 1 auto; - display: flex; - position: relative; - overflow: hidden; -} - -.vp-split.row { flex-direction: row; } -.vp-split.col { flex-direction: column; } - -.viewport-pane { - flex: 1 1 0; - position: relative; - border: var(--vp-space-s) solid var(--color-border); - background: var(--vp-background); - padding: var(--vp-space-l); - overflow: auto; - font-family: console; - transition: - border-color var(--vp-duration) var(--vp-easing), - box-shadow var(--vp-duration) var(--vp-easing), - background var(--vp-duration) var(--vp-easing); -} - -.vp-split > .viewport-pane { - transition: - flex var(--vp-duration) var(--vp-easing), - opacity var(--vp-duration) var(--vp-easing); -} - -.vp-no-transition, -.vp-no-transition * { - transition: none !important; -} - -.viewport-pane:before { - content: attr(data-title); - position: absolute; - top: var(--vp-space-s); - right: var(--vp-space-s); - opacity: var(--vp-opacity-medium); - pointer-events: none; -} - -.viewport-pane.focused { - border-color: var(--vp-color-primary-focus); - z-index: var(--vp-z-pane); -} - -.viewport-pane.focused:before { - opacity: var(--vp-opacity-active); - color: var(--color-highlight); -} - -.vp-divider { - background: var(--color-border); - opacity: var(--vp-opacity); - position: relative; - flex: 0 0 auto; -} - -.vp-divider.row { - width: var(--vp-space-l); - cursor: col-resize; -} - -.vp-divider.col { - height: var(--vp-space-l); - cursor: row-resize; -} - -.vp-divider:after { - content:''; - position: absolute; - inset: 0; - transition: - background var(--vp-duration) var(--vp-easing), - opacity var(--vp-duration) var(--vp-easing); - background: var(--color-border); -} - -.vp-divider.row:after { - background: var(--color-border); -} - -.vp-divider:hover:after { - background: var(--color-highlight); - opacity: var(--vp-opacity); -} - -.vp-divider.dragging:after { - background: var(--color-highlight); - opacity: var(--vp-opacity-active); -} - -.vp-help-overlay { - position: absolute; - top: var(--vp-space-s); - left: var(--vp-space-s); - opacity: var(--vp-opacity); - pointer-events: none; -} - -.vp-pane-toolbar { - position: absolute; - top: var(--vp-space-s); - right: var(--vp-space-s); - display: flex; - gap: var(--vp-space-s); - z-index: var(--vp-z-toolbar); -} - -.vp-pane-toolbar button { - padding: 0 var(--vp-space-l); - border: 1px solid var(--color-border); - background: var(--vp-background); - cursor: pointer; - display: inline-flex; - align-items: center; - justify-content: center; -} - -.vp-pane-toolbar button:hover { - background: var(--color-highlight); - color: var(--vp-color-black); - text-shadow: none; -} - -.vp-icon { - width: var(--vp-size-icon); - height: var(--vp-size-icon); - display: block; -} \ No newline at end of file diff --git a/site/info/uce-starter/js/u-tiling-viewport.js b/site/info/uce-starter/js/u-tiling-viewport.js deleted file mode 100644 index 3762033..0000000 --- a/site/info/uce-starter/js/u-tiling-viewport.js +++ /dev/null @@ -1,388 +0,0 @@ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - // AMD - define(['jquery'], factory); - } else if (typeof module === 'object' && module.exports) { - // CommonJS - module.exports = factory(require('jquery')); - } else { - // Browser globals - root.TilingViewportManager = factory(root.$); - } -}(typeof self !== 'undefined' ? self : this, function ($) { - 'use strict'; - - // Note: This module expects showPopupMenu to be available globally - // or you may need to adjust the dependency list above to include it - - let TilingViewportManager = function(container, options = {}) { - - let idCounter = 1, rootNode = null, focusedPane = null, containerEl = null; - let nextId = () => 'vp_' + (idCounter++); - let paneMeta = new Map(); - let pendingViewLoads = []; - let defaultoptions = { - minPaneSize: 100, - keyboard: true, - showHelp: true, - closeTransitionTimeout: 400, - toolbarButtons: ['split-v','split-h','views','close'], - standardViewList: [], - cssVars: { '--vp-duration': '.22s', '--vp-easing': 'ease' } - }; - options = Object.assign({}, defaultoptions, options); - - let createPane = (content, props = {}) => { - let id = nextId(); - let $el = $('
').attr('data-id', id); - if(props.title) $el.attr('data-title', props.title); - $el.html(content || `
Use Alt+<H V O X ↑ ← → ↓>
`) - .on('mousedown', () => focusPaneByEl($el[0])); - attachPaneToolbar($el[0]); - paneMeta.set(id, {id, canClose: true, canSplit: true, title: props.title, ...props}); - if(props.view?.screen) pendingViewLoads.push({id, view: props.view}); - return {type: 'pane', id, el: $el[0]}; - }; - - let buildInitial = () => { rootNode = createPane(); $(containerEl).html('').append(rootNode.el); focusPane(rootNode); }; - let focusPane = node => { if(!node || node.type !== 'pane') return; if(focusedPane?.el) $(focusedPane.el).removeClass('focused'); focusedPane = node; $(node.el).addClass('focused'); }; - let focusPaneByEl = el => focusPane(findNodeById(rootNode, $(el).attr('data-id'))); - let findNodeById = (node, id) => !node ? null : node.type === 'pane' ? (node.id === id ? node : null) : node.children.map(ch => findNodeById(ch, id)).find(r=>r); - let getNodeById = id => findNodeById(rootNode, id) || null; - let findParentPath = (node, id, path=[]) => !node ? null : node.type === 'pane' ? (node.id === id ? path : null) : node.children.map(ch => findParentPath(ch, id, path.concat(node))).find(r=>r); - let paneList = (node, acc=[]) => !node ? acc : node.type === 'pane' ? (acc.push(node), acc) : (node.children.forEach(ch => paneList(ch, acc)), acc); - let renormalizeSizes = splitNode => { let total = splitNode.sizes.reduce((a,b)=>a+b,0)||1; splitNode.sizes = splitNode.sizes.map(s=>s/total); }; - let replaceChild = (splitNode, oldChild, newChild) => { let i = splitNode.children.indexOf(oldChild); if(i>=0) splitNode.children.splice(i,1,newChild); }; - - let split = (direction, newPaneProps = {}) => { - if(!focusedPane) return; - let meta = paneMeta.get(focusedPane.id); - if(meta?.canSplit === false) return; - - let paneRect = focusedPane.el.getBoundingClientRect(); - let availableSpace = direction === 'row' ? paneRect.width : paneRect.height; - let requiredSpace = 2 * options.minPaneSize; - if(availableSpace < requiredSpace) { - //console.log(`Cannot split: available space ${availableSpace}px < required ${requiredSpace}px`); - return; - } - - let parentPath = findParentPath(rootNode, focusedPane.id); - let newPane = createPane(undefined, newPaneProps); - let animatedSplit = null, newIndex = -1; - if(!parentPath?.length) { - rootNode = {type:'split', direction, children:[focusedPane, newPane], sizes:[1,0]}; - animatedSplit = rootNode; newIndex = 1; - } else { - let parent = parentPath.at(-1); - if(parent.type === 'split' && parent.direction === direction) { - let idx = parent.children.indexOf(focusedPane); - parent.children.splice(idx+1, 0, newPane); - parent.sizes = parent.sizes || parent.children.map(()=>1); - parent.sizes.splice(idx+1, 0, 0); - renormalizeSizes(parent); - animatedSplit = parent; newIndex = idx+1; - } else if(parent.type === 'split' && parent.direction !== direction && parent.children.length === 1) { - parent.direction = direction; parent.children.push(newPane); parent.sizes = [1,0]; - animatedSplit = parent; newIndex = parent.children.length-1; - } else { - let idx = parent.children.indexOf(focusedPane); - let created = {type:'split', direction, children:[focusedPane, newPane], sizes:[1,0]}; - parent.children.splice(idx, 1, created); - animatedSplit = created; newIndex = 1; - } - } - render(); - if(animatedSplit && newIndex >= 0) { - requestAnimationFrame(() => requestAnimationFrame(() => { - animatedSplit.sizes = animatedSplit.children.map(()=>1); - renormalizeSizes(animatedSplit); - animatedSplit.children.forEach((ch,i) => ch.el && (ch.el.style.flex = `${animatedSplit.sizes[i]} 1 0`)); - })); - } - focusPane(newPane); return newPane; - }; - - let splitVertical = () => split('row'); - let splitHorizontal = () => split('col'); - - let closeFocused = () => { - if(!focusedPane) return; - let meta = paneMeta.get(focusedPane.id); - if(meta?.canClose === false) return; - if(rootNode === focusedPane) { buildInitial(); return; } - if(typeof meta?.onUnload === 'function') meta.onUnload(focusedPane.id); - if(typeof meta?.view?.onUnload === 'function') meta.view.onUnload(focusedPane.id); - let parentPath = findParentPath(rootNode, focusedPane.id); - if(!parentPath?.length) return; - let parent = parentPath.at(-1); - if(parent.type !== 'split') return; - let idx = parent.children.indexOf(focusedPane); - - let oldSizes = (parent.sizes || parent.children.map(()=>1)).slice(); - let oldSize = oldSizes[idx] || 0; - let remaining = 1 - oldSize; - let newSizes = oldSizes.slice(); - if(remaining > 0) { - for(let i=0;i ch.el && (ch.el.style.flex = `${parent.sizes[i]} 1 0`)); - if(focusedPane.el) { - focusedPane.el.style.transition = (focusedPane.el.style.transition || '') + ', opacity .18s ease'; - focusedPane.el.style.opacity = '0'; - } - let done = false; - let cleanup = () => { - if(done) return; done = true; - parent.children.splice(idx,1); - parent.sizes?.splice(idx,1); - paneMeta.delete(focusedPane.id); - if(parent.children.length === 1) { - let only = parent.children[0]; - parentPath.length === 1 ? rootNode = only : replaceChild(parentPath.at(-2), parent, only); - } else if(parent.sizes) renormalizeSizes(parent); - render(); focusPane(paneList(rootNode)[0]); - }; - let onEnd = ev => { if(ev.target === focusedPane.el && (ev.propertyName === 'opacity' || ev.propertyName === 'flex')) { focusedPane.el.removeEventListener('transitionend', onEnd); cleanup(); } }; - if(focusedPane.el) focusedPane.el.addEventListener('transitionend', onEnd); - setTimeout(() => cleanup(), 350); - }; - - let nextPane = (node, currentId, options={direction:1}) => { let list = paneList(node); if(!list.length) return null; let idx = list.findIndex(p=>p.id===(currentId||(focusedPane?.id)))||0; return list[(idx+options.direction+list.length)%list.length]; }; - let focusNext = () => { let n = nextPane(rootNode); if(n) focusPane(n); }; - let focusPrev = () => { let n = nextPane(rootNode, null, {direction:-1}); if(n) focusPane(n); }; - - let serialize = (node=rootNode) => { - let ser = n => !n ? null : n.type==='pane' ? - {type:'pane', id:n.id, title:paneMeta.get(n.id)?.title, props:{canClose:paneMeta.get(n.id)?.canClose!==false, canSplit:paneMeta.get(n.id)?.canSplit!==false}, view:paneMeta.get(n.id)?.view||null} : - {type:'split', direction:n.direction, sizes:(n.sizes||[]).slice(), children:n.children.map(ser)}; - return {focus: focusedPane?.id, layout: ser(node)}; - }; - - let restore = data => { - if(!data) return; - let wrapper = data.layout ? data : {layout:data}; - paneMeta.clear(); idCounter = 1; pendingViewLoads.length = 0; - let idNums = []; - let build = l => l && l.type==='pane' ? - (() => { let pane = createPane(undefined, {title:l.title, canClose:l.props?.canClose, canSplit:l.props?.canSplit, view:l.view}); - if(l.id) { pane.el.dataset.id = pane.id = l.id; let n=parseInt(l.id.split('_')[1],10); if(!isNaN(n)) idNums.push(n); } - let meta = paneMeta.get(pane.id); if(meta) { Object.assign(meta, l.props||{}, {title:l.title, view:l.view}); if(pane.el && l.title) pane.el.dataset.title = l.title; paneMeta.set(pane.id, meta); } - return pane; })() : - l && l.type==='split' ? {type:'split', direction:l.direction||'row', children:(l.children||[]).map(build).filter(Boolean), sizes:(l.sizes||[]).slice()} : null; - rootNode = build(wrapper.layout) || createPane(); - if(idNums.length) idCounter = Math.max(...idNums) + 1; - render(); - pendingViewLoads.forEach(v => v.view && loadView(v.id, v.view)); pendingViewLoads.length = 0; - focusPane(wrapper.focus ? findNodeById(rootNode, wrapper.focus) || paneList(rootNode)[0] : paneList(rootNode)[0]); - }; - - let render = () => { if(!containerEl) return; $(containerEl).empty().append(renderNode(rootNode)); injectHelpOverlay(); }; - - let renderNode = node => { - if(node.type==='pane') return node.el; - node.el = node.el || $('
')[0]; - $(node.el).empty().addClass(`vp-split ${node.direction}`); - if(!node.sizes || node.sizes.length !== node.children.length) { node.sizes = node.children.map(()=>1); renormalizeSizes(node); } - node.children.forEach((ch,i) => { - let chEl = renderNode(ch); $(chEl).css('flex', `${node.sizes[i]} 1 0`); node.el.appendChild(chEl); - if(i < node.children.length-1) { let div = $('
').addClass(`vp-divider ${node.direction}`)[0]; setupDivider(div, node, i); node.el.appendChild(div); } - }); - return node.el; - }; - - let setupDivider = (div, splitNode, leftIdx) => { - $(div).on('mousedown', e => { - e.preventDefault(); $(div).addClass('dragging'); - $(containerEl).addClass('vp-no-transition'); - let isRow = splitNode.direction === 'row'; - let startPos = isRow ? e.clientX : e.clientY; - let childRects = splitNode.children.map(ch => ch.el.getBoundingClientRect()); - let prop = isRow ? 'width' : 'height'; - let startPixels = childRects.map(r => r[prop]); - let [aStartPx, bStartPx] = [startPixels[leftIdx], startPixels[leftIdx+1]]; - let totalPixels = startPixels.reduce((a,b)=>a+b,0); - let onMove = ev => { - let curPos = isRow ? ev.clientX : ev.clientY; - let [newApx, newBpx] = [aStartPx + curPos - startPos, bStartPx - curPos + startPos]; - if(newApx < options.minPaneSize) [newApx, newBpx] = [options.minPaneSize, aStartPx + bStartPx - options.minPaneSize]; - if(newBpx < options.minPaneSize) [newApx, newBpx] = [aStartPx + bStartPx - options.minPaneSize, options.minPaneSize]; - startPixels[leftIdx] = newApx; startPixels[leftIdx+1] = newBpx; - splitNode.sizes = startPixels.map(p => p / totalPixels); - splitNode.children.forEach((ch,i)=> { - if(ch.el) { - let flexValue = `${splitNode.sizes[i]} 1 0`; - $(ch.el).css('flex', flexValue); - } - }); - }; - let onUp = () => { - $(div).removeClass('dragging'); - $(containerEl).removeClass('vp-no-transition'); - $(document).off('mousemove', onMove).off('mouseup', onUp); - }; - $(document).on('mousemove', onMove).on('mouseup', onUp); - }); - $(div).on('dblclick', () => { - $(containerEl).addClass('vp-no-transition'); - let len = splitNode.sizes.length; splitNode.sizes = splitNode.sizes.map(()=>1/len); - splitNode.children.forEach((ch,i)=> ch.el && $(ch.el).css('flex', `${splitNode.sizes[i]} 1 0`)); - setTimeout(() => $(containerEl).removeClass('vp-no-transition'), 0); - }); - }; - - let attachPaneToolbar = el => { - let bar = $('
').addClass('vp-pane-toolbar').html(` - - - - `)[0]; - el.appendChild(bar); - $(bar).on('mousedown', ev => ev.stopPropagation()); - $(bar).on('click', ev => { ev.stopPropagation(); focusPaneByEl(el); - let button = ev.target.closest('button[data-act]'); - let act = button ? button.getAttribute('data-act') : null; - if(act==='split-v') splitVertical(); else if(act==='split-h') splitHorizontal(); else if(act==='close') closeFocused(); - else if(act==='views') { - // compute button position - let rect = button.getBoundingClientRect(); - let items = options.standardViewList.slice(); - showPopupMenu(rect.left, rect.bottom, items, { onSelect: it => { - // support string or object {screen} - let view = typeof it === 'string' ? {screen: it} : (it.screen ? it : {screen: it}); - loadView(el.dataset.id, view); - }, container: document.body, emptyText: 'No views available' }); - } - }); - refreshToolbarState(el.dataset.id); - }; - - let refreshToolbarState = paneId => { - let meta = paneMeta.get(paneId); let el = $(containerEl).find(`.viewport-pane[data-id="${paneId}"]`)[0]; - if(!el) return; let bar = $(el).find('.vp-pane-toolbar')[0]; if(!bar) return; - let [canSplit, canClose] = [!meta||meta.canSplit!==false, !meta||meta.canClose!==false]; - ['split-v','split-h'].forEach(act => { let btn = $(bar).find(`[data-act="${act}"]`)[0]; if(btn) { btn.disabled = !canSplit; $(btn).toggleClass('disabled', !canSplit); } }); - let btnC = $(bar).find('[data-act="close"]')[0]; if(btnC) { btnC.disabled = !canClose; $(btnC).toggleClass('disabled', !canClose); } - }; - - let setPaneProps = (paneId, props) => { let meta = paneMeta.get(paneId); if(!meta) return; Object.assign(meta, props); - if(props.title) { let el = $(containerEl).find(`.viewport-pane[data-id="${paneId}"]`)[0]; if(el) el.dataset.title = props.title; } - if(typeof props.onUnload === 'function') meta.onUnload = props.onUnload; - paneMeta.set(paneId, meta); refreshToolbarState(paneId); }; - let getPaneProps = paneId => paneMeta.get(paneId); - - let focusDirection = (dx, dy) => { - if(!focusedPane) return; - let panes = Array.from(containerEl.querySelectorAll('.viewport-pane')); - let cur = focusedPane.el.getBoundingClientRect(); - let candidates = panes.filter(p => p !== focusedPane.el).map(p => { - let r = p.getBoundingClientRect(); - if(dx) { - if(dx > 0 && r.left < cur.right-1 || dx < 0 && r.right > cur.left+1) return null; - let overlap = Math.max(0, Math.min(cur.bottom, r.bottom) - Math.max(cur.top, r.top)); - let primaryDist = dx > 0 ? r.left - cur.right : cur.left - r.right; - if(primaryDist < -1) return null; - return {el:p, score: primaryDist*1000 + (cur.height - overlap)}; - } - if(dy > 0 && r.top < cur.bottom-1 || dy < 0 && r.bottom > cur.top+1) return null; - let overlap = Math.max(0, Math.min(cur.right, r.right) - Math.max(cur.left, r.left)); - let primaryDist = dy > 0 ? r.top - cur.bottom : cur.top - r.bottom; - if(primaryDist < -1) return null; - return {el:p, score: primaryDist*1000 + (cur.width - overlap)}; - }).filter(Boolean); - if(candidates.length) return focusPaneByEl(candidates.sort((a,b) => a.score - b.score)[0].el); - let [cx, cy] = [cur.left + cur.width/2, cur.top + cur.height/2]; - let fallback = panes.filter(p => p !== focusedPane.el).map(p => { - let r = p.getBoundingClientRect(); let [px, py] = [r.left + r.width/2, r.top + r.height/2]; - let [vx, vy] = [px-cx, py-cy]; - if(dx && Math.sign(vx) !== Math.sign(dx) || dy && Math.sign(vy) !== Math.sign(dy)) return null; - return {el:p, score: (dx ? Math.abs(vx) : Math.abs(vy))*2 + (dx ? Math.abs(vy) : Math.abs(vx))}; - }).filter(Boolean); - if(fallback.length) focusPaneByEl(fallback.sort((a,b) => a.score - b.score)[0].el); - }; - - let injectHelpOverlay = () => { - if(!options.showHelp) return; - if(!containerEl.querySelector('.vp-help-overlay')) containerEl.appendChild(Object.assign(document.createElement('div'), {className:'vp-help-overlay', innerHTML:options.hint_text || ``})); - }; - - let getPaneEl = id => findNodeById(rootNode, id)?.el || null; - - let openViewsPopupForPane = (paneId) => { - let node = findNodeById(rootNode, paneId || focusedPane?.id); - if(!node || !node.el) return; - let rect = node.el.getBoundingClientRect(); - let x = Math.max(8, rect.right - 80); - let y = rect.top + 24; - let items = options.standardViewList.slice(); - showPopupMenu(x, y, items, { onSelect: it => { - let view = typeof it === 'string' ? {screen: it} : (it.screen ? it : {screen: it}); - loadView(node.id, view); - }, container: document.body, emptyText: 'No views available' }); - }; - - let loadView = (paneId, view) => { - let node = findNodeById(rootNode, paneId); - if(!node || !node.el) return; // nothing to load into - let meta = paneMeta.get(paneId); - try { if(meta && typeof meta.onUnload === 'function') meta.onUnload(paneId); if(meta && meta.view && typeof meta.view.onUnload === 'function') meta.view.onUnload(paneId); } catch(e){ console.error('onUnload error', e); } - if(meta) meta.view = view; - node.el.innerHTML = `
Loading ${view.screen||'...'}...
`; - $(node.el).load(`screens/${view.screen}.html?v=${Date.now()}`, {diff:true, onLoad:()=>$.emit('view:loaded',{paneId,view})}); - }; - - let handleKeys = e => { - if(!e.altKey || !options.keyboard) return; - let actions = { - 'KeyV':()=>splitVertical(),'v':()=>splitVertical(),'V':()=>splitVertical(), - 'KeyH':()=>splitHorizontal(),'h':()=>splitHorizontal(),'H':()=>splitHorizontal(), - 'KeyX':()=>closeFocused(),'x':()=>closeFocused(),'X':()=>closeFocused(), - 'KeyO':()=>openViewsPopupForPane(),'o':()=>openViewsPopupForPane(), 'O':()=>openViewsPopupForPane(), - 'ArrowRight':()=>focusDirection(1,0),'ArrowLeft':()=>focusDirection(-1,0),'ArrowUp':()=>focusDirection(0,-1),'ArrowDown':()=>focusDirection(0,1),'Tab':()=>focusNext() - }; - if(actions[e.code] || actions[e.key]) { - (actions[e.code] || actions[e.key])(); - e.preventDefault(); - } - }; - - containerEl = typeof container === 'string' ? document.querySelector(container) : container; - if(!containerEl) throw new Error('TilingViewportManager: container not found'); - if(options.cssVars) Object.keys(options.cssVars).forEach(k => containerEl.style.setProperty(k, options.cssVars[k])); - buildInitial(); - if(options.keyboard) document.addEventListener('keydown', handleKeys); - - this.splitVertical = splitVertical; - this.splitHorizontal = splitHorizontal; - this.closeFocused = closeFocused; - this.focusNext = focusNext; - this.focusPrev = focusPrev; - this.serialize = serialize; - this.restore = restore; - this.setPaneProps = setPaneProps; - this.getPaneProps = getPaneProps; - this.options = options; - this.loadView = loadView; - this.getPaneEl = getPaneEl; - this.getNodeById = getNodeById; - - Object.defineProperty(this, 'layout', { get: () => serialize(), set: d => restore(d) }); - Object.defineProperty(this, 'focused', { get: () => focusedPane?.id }); - }; - - return TilingViewportManager; -})); \ No newline at end of file diff --git a/site/info/uce-starter/js/u-timeseries-chart.js b/site/info/uce-starter/js/u-timeseries-chart.js deleted file mode 100644 index b19f3eb..0000000 --- a/site/info/uce-starter/js/u-timeseries-chart.js +++ /dev/null @@ -1,354 +0,0 @@ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof module === 'object' && module.exports) { - module.exports = factory(); - } else { - root.UTimeSeriesChart = factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { - 'use strict'; - const globalScope = typeof globalThis !== 'undefined' ? globalThis : (typeof window !== 'undefined' ? window : this); - - class TimeSeriesChart { - constructor(canvasOrId, options = {}) { - this.canvas = typeof canvasOrId === 'string' ? document.getElementById(canvasOrId) : canvasOrId; - if (!this.canvas || !this.canvas.getContext) { - throw new Error('UTimeSeriesChart requires a canvas element'); - } - - this.ctx = this.canvas.getContext('2d'); - const theme = this.resolveThemeColors(); - this.options = Object.assign({ - xAxisLabel: 'Time', - yAxisLeftLabel: 'Value', - yAxisRightLabel: '', - yAxisLeftFormat: 'number', - yAxisRightFormat: 'number', - padding: { top: 18, right: 62, bottom: 34, left: 58 }, - gridColor: theme.gridColor, - axisColor: theme.axisColor, - textColor: theme.textColor, - legendBackground: theme.legendBackground, - legendTextColor: theme.legendTextColor, - tooltipBackground: theme.tooltipBackground, - tooltipBorder: theme.tooltipBorder, - tooltipTitleColor: theme.tooltipTitleColor, - tooltipTextColor: theme.tooltipTextColor, - hoverLineColor: 'rgba(255,255,255,0.35)', - }, options); - - this.series = []; - this.xLabels = []; - this.hoverIndex = null; - this.hoverX = 0; - this.width = 0; - this.height = 0; - - this.onMouseMove = this.onMouseMove.bind(this); - this.onMouseLeave = this.onMouseLeave.bind(this); - this.onResize = this.onResize.bind(this); - - this.canvas.addEventListener('mousemove', this.onMouseMove); - this.canvas.addEventListener('mouseleave', this.onMouseLeave); - globalScope.addEventListener('resize', this.onResize); - if (typeof ResizeObserver !== 'undefined') { - this.resizeObserver = new ResizeObserver(this.onResize); - this.resizeObserver.observe(this.canvas); - } - - this.resize(); - } - - resolveThemeColors() { - const styles = globalScope.getComputedStyle ? globalScope.getComputedStyle(document.documentElement) : null; - const pick = function (name, fallback) { - if (!styles) return fallback; - const value = styles.getPropertyValue(name).trim(); - return value || fallback; - }; - return { - gridColor: pick('--border', 'rgba(148, 163, 184, 0.20)'), - axisColor: pick('--border-hover', pick('--border', 'rgba(148, 163, 184, 0.42)')), - textColor: pick('--text-secondary', '#64748b'), - legendBackground: pick('--surface', 'rgba(15, 23, 42, 0.72)'), - legendTextColor: pick('--text-primary', '#0f172a'), - tooltipBackground: pick('--surface', '#0f172a'), - tooltipBorder: pick('--border', 'rgba(148, 163, 184, 0.30)'), - tooltipTitleColor: pick('--primary', '#3b82f6'), - tooltipTextColor: pick('--text-primary', '#0f172a'), - }; - } - - destroy() { - this.canvas.removeEventListener('mousemove', this.onMouseMove); - this.canvas.removeEventListener('mouseleave', this.onMouseLeave); - globalScope.removeEventListener('resize', this.onResize); - if (this.resizeObserver) { - this.resizeObserver.disconnect(); - } - } - - onResize() { - this.resize(); - } - - onMouseLeave() { - this.hoverIndex = null; - this.draw(); - } - - resize() { - const rect = this.canvas.getBoundingClientRect(); - const cssWidth = Math.max(280, Math.round(rect.width || this.canvas.width || 640)); - const cssHeight = Math.max(180, Math.round(rect.height || this.canvas.height || 320)); - const pixelRatio = globalScope.devicePixelRatio || 1; - - this.width = cssWidth; - this.height = cssHeight; - this.canvas.width = Math.round(cssWidth * pixelRatio); - this.canvas.height = Math.round(cssHeight * pixelRatio); - this.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); - this.draw(); - } - - setData(series, xLabels = []) { - this.series = (Array.isArray(series) ? series : []).map((item) => ({ - key: item.key || '', - label: item.label || 'Series', - color: item.color || '#60a5fa', - axis: item.axis === 'right' ? 'right' : 'left', - unit: item.unit || '', - format: item.format || '', - maxHint: Number(item.maxHint || 0), - decimals: Number.isInteger(item.decimals) ? item.decimals : 2, - values: Array.isArray(item.values) ? item.values.map((value) => Number(value || 0)) : [], - })); - this.xLabels = Array.isArray(xLabels) ? xLabels : []; - this.draw(); - } - - getPlotRect() { - const padding = this.options.padding; - return { - x: padding.left, - y: padding.top, - w: this.width - padding.left - padding.right, - h: this.height - padding.top - padding.bottom, - }; - } - - getMaxForAxis(axis) { - const relevant = this.series.filter((item) => item.axis === axis); - if (!relevant.length) return 1; - let max = 1; - relevant.forEach((item) => { - const localMax = Math.max(...(item.values.length ? item.values : [0]), item.maxHint || 0, 1); - if (localMax > max) max = localMax; - }); - return max; - } - - xForIndex(index, pointCount, plot) { - if (pointCount <= 1) return plot.x; - return plot.x + (index / (pointCount - 1)) * plot.w; - } - - yForValue(value, axisMax, plot) { - const clamped = Math.max(0, Number(value || 0)); - return plot.y + plot.h - ((clamped / axisMax) * plot.h); - } - - formatValue(value, format, unit, decimals) { - const number = Number(value || 0); - if (globalScope.UFormat) { - if (format === 'bytes' && globalScope.UFormat.formatBytes) return globalScope.UFormat.formatBytes(number); - if (format === 'disk-bytes' && globalScope.UFormat.formatDiskBytes) return globalScope.UFormat.formatDiskBytes(number); - if (format === 'count' && globalScope.UFormat.formatCount) return globalScope.UFormat.formatCount(number); - if (format === 'duration-ms' && globalScope.UFormat.formatDurationMs) return globalScope.UFormat.formatDurationMs(number); - } - return `${number.toFixed(decimals)}${unit || ''}`; - } - - drawGridAndAxes(plot, maxLeft, maxRight) { - const ctx = this.ctx; - ctx.strokeStyle = this.options.gridColor; - ctx.lineWidth = 1; - - for (let index = 0; index <= 4; index += 1) { - const y = plot.y + (plot.h / 4) * index; - ctx.beginPath(); - ctx.moveTo(plot.x, y); - ctx.lineTo(plot.x + plot.w, y); - ctx.stroke(); - - const leftValue = maxLeft - ((maxLeft / 4) * index); - const leftTick = this.formatValue(leftValue, this.options.yAxisLeftFormat, '', 1); - ctx.fillStyle = this.options.textColor; - ctx.font = '11px Inter, sans-serif'; - const leftWidth = ctx.measureText(leftTick).width; - ctx.fillText(leftTick, Math.max(4, plot.x - leftWidth - 8), y + 4); - - if (this.options.yAxisRightLabel) { - const rightValue = maxRight - ((maxRight / 4) * index); - const rightTick = this.formatValue(rightValue, this.options.yAxisRightFormat, '', 1); - ctx.fillText(rightTick, plot.x + plot.w + 8, y + 4); - } - } - - ctx.strokeStyle = this.options.axisColor; - ctx.beginPath(); - ctx.moveTo(plot.x, plot.y); - ctx.lineTo(plot.x, plot.y + plot.h); - ctx.lineTo(plot.x + plot.w, plot.y + plot.h); - ctx.stroke(); - - ctx.fillStyle = this.options.textColor; - ctx.font = '12px Inter, sans-serif'; - ctx.save(); - ctx.translate(14, plot.y + (plot.h / 2)); - ctx.rotate(-Math.PI / 2); - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.fillText(this.options.yAxisLeftLabel, 0, 0); - ctx.restore(); - - if (this.options.yAxisRightLabel) { - ctx.save(); - ctx.translate(this.width - 14, plot.y + (plot.h / 2)); - ctx.rotate(Math.PI / 2); - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - ctx.fillText(this.options.yAxisRightLabel, 0, 0); - ctx.restore(); - } - - const xLabel = this.options.xAxisLabel; - const xLabelWidth = ctx.measureText(xLabel).width; - ctx.fillText(xLabel, plot.x + plot.w - xLabelWidth, this.height - 10); - } - - drawSeries(plot, maxLeft, maxRight) { - const ctx = this.ctx; - const pointCount = Math.max(...this.series.map((item) => item.values.length), 0); - if (pointCount <= 0) return; - - this.series.forEach((item) => { - if (!item.values.length) return; - const axisMax = item.axis === 'right' ? maxRight : maxLeft; - ctx.beginPath(); - item.values.forEach((value, index) => { - const x = this.xForIndex(index, item.values.length, plot); - const y = this.yForValue(value, axisMax, plot); - if (index === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); - }); - ctx.strokeStyle = item.color; - ctx.lineWidth = 2; - ctx.stroke(); - }); - - if (this.series.length > 1) { - ctx.fillStyle = this.options.legendBackground; - ctx.fillRect(plot.x + 4, plot.y + 4, Math.min(plot.w - 8, 320), 24); - let offsetX = plot.x + 12; - this.series.forEach((item) => { - ctx.fillStyle = item.color; - ctx.fillRect(offsetX, plot.y + 13, 14, 3); - offsetX += 20; - ctx.fillStyle = this.options.legendTextColor; - ctx.font = '11px Inter, sans-serif'; - ctx.fillText(item.label, offsetX, plot.y + 17); - offsetX += ctx.measureText(item.label).width + 18; - }); - } - } - - drawHover(plot, maxLeft, maxRight) { - if (this.hoverIndex == null) return; - const ctx = this.ctx; - const pointCount = Math.max(...this.series.map((item) => item.values.length), 0); - if (pointCount <= 0) return; - - const index = Math.max(0, Math.min(pointCount - 1, this.hoverIndex)); - const x = this.xForIndex(index, pointCount, plot); - - ctx.strokeStyle = this.options.hoverLineColor; - ctx.lineWidth = 1; - ctx.beginPath(); - ctx.moveTo(x, plot.y); - ctx.lineTo(x, plot.y + plot.h); - ctx.stroke(); - - const lines = []; - lines.push(this.xLabels[index] || `Sample ${index + 1}`); - - this.series.forEach((item) => { - if (index >= item.values.length) return; - const axisMax = item.axis === 'right' ? maxRight : maxLeft; - const value = item.values[index] ?? 0; - const y = this.yForValue(value, axisMax, plot); - ctx.fillStyle = item.color; - ctx.beginPath(); - ctx.arc(x, y, 3.5, 0, Math.PI * 2); - ctx.fill(); - lines.push(`${item.label}: ${this.formatValue(value, item.format || (item.axis === 'right' ? this.options.yAxisRightFormat : this.options.yAxisLeftFormat), item.unit || '', item.decimals)}`); - }); - - ctx.font = '11px Inter, sans-serif'; - const padding = 8; - const lineHeight = 14; - const tooltipWidth = Math.max(...lines.map((line) => ctx.measureText(line).width)) + padding * 2; - const tooltipHeight = lines.length * lineHeight + padding * 2 - 2; - let tooltipX = this.hoverX + 12; - let tooltipY = plot.y + 8; - - if (tooltipX + tooltipWidth > this.width - 4) tooltipX = this.hoverX - tooltipWidth - 12; - if (tooltipX < 4) tooltipX = 4; - if (tooltipY + tooltipHeight > this.height - 4) tooltipY = this.height - tooltipHeight - 4; - - ctx.fillStyle = this.options.tooltipBackground; - ctx.fillRect(tooltipX, tooltipY, tooltipWidth, tooltipHeight); - ctx.strokeStyle = this.options.tooltipBorder; - ctx.strokeRect(tooltipX, tooltipY, tooltipWidth, tooltipHeight); - - lines.forEach((line, lineIndex) => { - ctx.fillStyle = lineIndex === 0 ? this.options.tooltipTitleColor : this.options.tooltipTextColor; - ctx.fillText(line, tooltipX + padding, tooltipY + padding + 10 + lineIndex * lineHeight); - }); - } - - onMouseMove(event) { - const rect = this.canvas.getBoundingClientRect(); - const x = event.clientX - rect.left; - this.hoverX = x; - - const plot = this.getPlotRect(); - const pointCount = Math.max(...this.series.map((item) => item.values.length), 0); - if (pointCount <= 0) { - this.hoverIndex = null; - this.draw(); - return; - } - - const relative = Math.max(0, Math.min(plot.w, x - plot.x)); - this.hoverIndex = pointCount <= 1 ? 0 : Math.round((relative / plot.w) * (pointCount - 1)); - this.draw(); - } - - draw() { - const ctx = this.ctx; - ctx.clearRect(0, 0, this.width, this.height); - - const plot = this.getPlotRect(); - if (plot.w <= 0 || plot.h <= 0) return; - const maxLeft = this.getMaxForAxis('left'); - const maxRight = this.getMaxForAxis('right'); - - this.drawGridAndAxes(plot, maxLeft, maxRight); - this.drawSeries(plot, maxLeft, maxRight); - this.drawHover(plot, maxLeft, maxRight); - } - } - - return TimeSeriesChart; -})); \ No newline at end of file diff --git a/site/info/uce-starter/js/u-workspace-shell.js b/site/info/uce-starter/js/u-workspace-shell.js deleted file mode 100644 index 90fbd31..0000000 --- a/site/info/uce-starter/js/u-workspace-shell.js +++ /dev/null @@ -1,68 +0,0 @@ -(function (root, factory) { - if (typeof define === 'function' && define.amd) { - define([], factory); - } else if (typeof module === 'object' && module.exports) { - module.exports = factory(); - } else { - root.UWorkspaceShell = factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { - 'use strict'; - const globalScope = typeof globalThis !== 'undefined' ? globalThis : (typeof window !== 'undefined' ? window : this); - - function getElement(target) { - if (!target) return null; - if (typeof target === 'string') return document.getElementById(target); - return target && target.nodeType === 1 ? target : null; - } - - function bindShell(options) { - const sidebar = getElement(options.sidebarId || options.sidebar); - const overlay = getElement(options.overlayId || options.overlay); - const toggle = getElement(options.toggleButtonId || options.toggle); - const closeOnNav = options.closeOnNav !== false; - - if (!sidebar || !overlay) return null; - - function setOpen(open) { - sidebar.classList.toggle('is-open', !!open); - overlay.classList.toggle('is-open', !!open); - } - - function toggleOpen() { - setOpen(!sidebar.classList.contains('is-open')); - } - - if (toggle) { - toggle.addEventListener('click', toggleOpen); - } - - overlay.addEventListener('click', function () { - setOpen(false); - }); - - if (closeOnNav) { - sidebar.querySelectorAll('a').forEach(function (link) { - link.addEventListener('click', function () { - setOpen(false); - }); - }); - } - - globalScope.addEventListener('resize', function () { - if (globalScope.innerWidth > 860) { - setOpen(false); - } - }); - - return { - open: function () { setOpen(true); }, - close: function () { setOpen(false); }, - toggle: toggleOpen, - }; - } - - return { - init: bindShell, - }; -})); \ No newline at end of file diff --git a/site/info/uce-starter/js/u-wsconnection.js b/site/info/uce-starter/js/u-wsconnection.js deleted file mode 100755 index 9c3b40f..0000000 --- a/site/info/uce-starter/js/u-wsconnection.js +++ /dev/null @@ -1,111 +0,0 @@ -(function (root, factory) { - if (typeof exports === 'object' && typeof module !== 'undefined') { - module.exports = factory(); - } else if (typeof define === 'function' && define.amd) { - define([], factory); - } else { - root.Connection = factory(); - } -}(typeof self !== 'undefined' ? self : this, function () { - -var Connection = { - - auto_reconnect : false, - established : false, - - update_indicator : (status) => { - var status_colors = { - 'offline' : 'red', - 'online' : 'lightgreen', - 'error' : 'DarkOrange', - }; - $('#connection-status').text(status).css('color', status_colors[status] || 'gray'); - }, - - debug : true, - auto_reconnect : true, - cmd_waiting_rels : {}, - - server_url : '', - - init : () => { - new EventSystem(Connection); - }, - - start : (url = null) => { - - if(url) Connection.server_url = url; - - Connection.update_indicator('offline'); - if(Connection.socket) Connection.socket.close(); - Connection.socket = new WebSocket(Connection.server_url); - Connection.socket.onmessage = function(rawmsg) { - var msg = JSON.parse(rawmsg.data); - if(Connection.debug) console.log('CONNECTION MSG', msg); - if(msg.type) Connection.trigger(msg.type, msg); - Connection.trigger('message', msg); - } - Connection.socket.onclose = function() { - Connection.update_indicator('offline'); - if(Connection.debug) console.log('CONNECTION CLOSED'); - Connection.established = false; - Connection.trigger('close', {}); - } - Connection.socket.onerror = function(error) { - Connection.update_indicator('error'); - console.error('CONNECTION', error); - Connection.established = false; - } - Connection.socket.onopen = function() { - Connection.update_indicator('online'); - if(Connection.debug) console.log('CONNECTION ESTABLISHED'); - Connection.established = true; - Connection.trigger('open', {}); - } - setTimeout(Connection.reconnect, 2000); - - }, - - deauth : () => { - Game.session = {}; - }, - - reconnect : () => { - if(!Connection.established && Connection.auto_reconnect) - Connection.start(); - else - setTimeout(Connection.reconnect, 2000); - }, - - queue : [], - - dequeue : () => { - var dq = Connection.queue; - Connection.queue = []; - dq.forEach(function(fm) { - Connection.send(fm); - }); - }, - - send : (msg) => { - if(Connection.established) { - if(typeof msg == 'function') - msg(); - else - Connection.socket.send(JSON.stringify(msg)); - } else { - Connection.queue.push(msg); - } - }, - - close : () => { - Connection.auto_reconnect = false; - Connection.socket.close(); - }, - -} - -return Connection; - -})); - diff --git a/site/info/uce-starter/lib/app.uce b/site/info/uce-starter/lib/app.uce deleted file mode 100644 index 0a2d92f..0000000 --- a/site/info/uce-starter/lib/app.uce +++ /dev/null @@ -1,418 +0,0 @@ -#load "../config/settings.uce" -#load "user.class.h" - -String app_fs_root(Request& context) -{ - String root = context.var["app"]["fs_root"].to_string(); - if(root == "") - root = cwd_get(); - return(root); -} - -String app_script_url(Request& context) -{ - String url = context.var["app"]["script_url"].to_string(); - if(url == "") - url = first(context.params["DOCUMENT_URI"], context.params["SCRIPT_NAME"]); - return(url); -} - -String app_base_url(Request& context) -{ - String base = context.var["app"]["base_url"].to_string(); - if(base == "") - { - base = dirname(app_script_url(context)); - if(base == "") - base = "/"; - if(base[base.length() - 1] != '/') - base.append(1, '/'); - } - return(base); -} - -String app_fs_path(String relative, Request& context) -{ - return(path_join(app_fs_root(context), relative)); -} - -String app_link(String path, Request& context); -String app_link(String path, StringMap params, Request& context); -void app_init(Request& context); - -String app_first_route_segment(Request& context) -{ - String query = context.params["QUERY_STRING"]; - for(auto part : split(query, "&")) - { - if(part == "") - continue; - if(part.find("=") == String::npos) - return(uri_decode(part)); - } - return(""); -} - -DTree app_make_route(Request& context) -{ - DTree route; - String path = app_first_route_segment(context); - path = trim(path); - while(path.length() > 0 && path[0] == '/') - path = path.substr(1); - while(path.length() > 0 && path[path.length() - 1] == '/') - path = path.substr(0, path.length() - 1); - if(path == "") - path = "index"; - route["l_path"] = path; - route["page"] = nibble(path, "/"); - if(route["page"].to_string() == "") - route["page"] = "index"; - return(route); -} - -DTree app_resolve_view(Request& context, String base_dir = "views") -{ - DTree result; - DTree route = context.var["app"]["route"]; - String lpath = first(route["l_path"].to_string(), "index"); - String base = trim(base_dir); - if(base != "" && base[base.length() - 1] == '/') - base = base.substr(0, base.length() - 1); - - String exact = base + "/" + lpath + ".uce"; - if(file_exists(exact)) - { - result["file"] = exact; - return(result); - } - - String dir_index = base + "/" + lpath + "/index.uce"; - if(file_exists(dir_index)) - { - result["file"] = dir_index; - return(result); - } - - auto parts = split(lpath, "/"); - if(parts.size() > 1) - { - String param = parts.back(); - parts.pop_back(); - String parent = join(parts, "/"); - String parent_index = base + "/" + parent + "/index.uce"; - if(file_exists(parent_index)) - { - result["file"] = parent_index; - result["param"] = param; - return(result); - } - } - - return(result); -} - -void app_register_css(String path, Request& context) -{ - context.var["app"]["assets"]["css"][path] = path; -} - -void app_register_js(String path, Request& context) -{ - context.var["app"]["assets"]["js"][path] = path; -} - -String app_asset_url(String path, Request& context) -{ - String url = app_base_url(context) + path; - String fs_path = app_fs_path(path, context); - if(file_exists(fs_path)) - url += "?v=" + std::to_string((u64)file_mtime(fs_path)); - return(url); -} - -void app_render_registered_css(Request& context) -{ - context.var["app"]["assets"]["css"].each([&](DTree item, String key) { - String path = item.to_string(); - if(path != "") - { - <> - } - }); -} - -void app_render_registered_js(Request& context) -{ - context.var["app"]["assets"]["js"].each([&](DTree item, String key) { - String path = item.to_string(); - if(path != "") - { - <> - } - }); -} - -String app_link(String path, Request& context) -{ - StringMap params; - return(app_link(path, params, context)); -} - -String app_link(String path, StringMap params, Request& context) -{ - String query = ""; - path = trim(path); - if(path != "") - query = uri_encode(path); - String extra = encode_query(params); - if(query != "" && extra != "") - query += "&" + extra; - else if(query == "") - query = extra; - String url = app_script_url(context); - if(query != "") - url += "?" + query; - return(url); -} - -void app_redirect(String path, Request& context) -{ - context.set_status(302, "Found"); - context.header["Location"] = app_link(path, context); -} - -void app_not_found(String message, Request& context) -{ - context.set_status(404, "Not Found"); - context.var["app"]["error"] = message; - context.var["app"]["page_title"] = "404 Not Found"; -} - -String app_menu_href(String menu_key, DTree menu_item, Request& context) -{ - if(menu_item["external"].to_string() != "") - return("/" + menu_key); - return(app_link(menu_key, context)); -} - -String app_html_class(Request& context) -{ - String classes = "no-js"; - if(context.cfg.get_by_path("theme/mode").to_string() == "dark") - classes += " dark-theme"; - return(classes); -} - -String app_page_main_html(Request& context) -{ - String main_html = context.call["main_html"].to_string(); - if(main_html == "") - main_html = context.var["app"]["fragments"]["main"].to_string(); - return(main_html); -} - -bool app_bool_value(DTree value, bool fallback = false) -{ - String raw = trim(value.to_string()); - if(raw == "") - return(fallback); - return( - raw != "0" && - raw != "false" && - raw != "FALSE" && - raw != "False" && - raw != "(false)" && - raw != "no" && - raw != "NO" && - raw != "No" - ); -} - -bool app_request_embed_mode(Request& context) -{ - return(app_bool_value(context.var["app"]["embed_mode"])); -} - -bool app_page_embed_mode(Request& context) -{ - String embed_value = context.call["embed_mode"].to_string(); - if(embed_value != "") - return(app_bool_value(context.call["embed_mode"])); - return(app_request_embed_mode(context)); -} - -String app_theme_page_component(Request& context) -{ - String page_type = first(context.var["app"]["page_type"].to_string(), "html"); - if(page_type == "blank") - return("themes/common/page.blank.uce"); - if(page_type == "json") - return("themes/common/page.json.uce"); - - String theme_path = context.cfg.get_by_path("theme/path").to_string(); - if(theme_path == "") - return(""); - if(theme_path[theme_path.length() - 1] != '/') - theme_path.append(1, '/'); - return(theme_path + "page.html.uce"); -} - -void app_render_page(Request& context) -{ - if(context.flags.status >= 300 && context.flags.status < 400) - return; - - DTree page_props; - page_props["main_html"] = context.var["app"]["fragments"]["main"]; - if(context.var["app"]["json"].get_type_name() == "array") - page_props["json"] = context.var["app"]["json"]; - - String page_component = app_theme_page_component(context); - if(page_component != "" && file_exists(page_component)) - { - print(component(page_component, page_props, context)); - return; - } - - context.set_status(500, "Internal Server Error"); - context.header["Content-Type"] = "text/plain; charset=utf-8"; - print("UCE app is missing the page template component: " + page_component); -} - -// Backward-compatible aliases for older starter example units. -using StarterUser = AppUser; - -void starter_boot(Request& context) -{ - app_init(context); -} - -String starter_link(String path, Request& context) -{ - return(app_link(path, context)); -} - -String starter_link(String path, StringMap params, Request& context) -{ - return(app_link(path, params, context)); -} - -void starter_register_css(String path, Request& context) -{ - app_register_css(path, context); -} - -void starter_register_js(String path, Request& context) -{ - app_register_js(path, context); -} - -String starter_asset_url(String path, Request& context) -{ - return(app_asset_url(path, context)); -} - -void starter_render_registered_css(Request& context) -{ - app_render_registered_css(context); -} - -void starter_render_registered_js(Request& context) -{ - app_render_registered_js(context); -} - -bool starter_page_embed_mode(Request& context) -{ - return(app_page_embed_mode(context)); -} - -String starter_page_main_html(Request& context) -{ - return(app_page_main_html(context)); -} - -String starter_html_class(Request& context) -{ - return(app_html_class(context)); -} - -String starter_menu_href(String menu_key, DTree menu_item, Request& context) -{ - return(app_menu_href(menu_key, menu_item, context)); -} - -void starter_render_page(Request& context) -{ - app_render_page(context); -} - -void starter_redirect(String path, Request& context) -{ - app_redirect(path, context); -} - -void starter_not_found(String message, Request& context) -{ - app_not_found(message, context); -} - -DTree starter_make_route(Request& context) -{ - return(app_make_route(context)); -} - -DTree starter_resolve_view(Request& context, String base_dir = "views") -{ - return(app_resolve_view(context, base_dir)); -} - -void app_init(Request& context) -{ - if(context.var["app"]["booted"].to_string() == "1") - return; - - context.var["app"]["booted"] = "1"; - context.var["app"]["fs_root"] = cwd_get(); - context.var["app"]["script_url"] = first(context.params["DOCUMENT_URI"], context.params["SCRIPT_NAME"]); - - String base_url = dirname(context.var["app"]["script_url"].to_string()); - if(base_url == "") - base_url = "/"; - if(base_url[base_url.length() - 1] != '/') - base_url.append(1, '/'); - context.var["app"]["base_url"] = base_url; - - DTree config = get_config(); - String requested_theme = first(context.get["theme"], context.cookies["app_theme"], config["theme"]["key"].to_string()); - if(config["theme"]["options"][requested_theme].to_string() == "" && config["theme"]["options"][requested_theme].get_type_name() != "array") - requested_theme = config["theme"]["key"].to_string(); - - config["theme"]["options"][requested_theme].each([&](DTree item, String key) { - config["theme"][key] = item; - }); - config["theme"]["key"] = requested_theme; - context.cfg = config; - context.var["cfg"].set_reference(&context.cfg); - context.var["app"]["config"].set_reference(&context.cfg); - context.var["app"]["route"] = app_make_route(context); - context.var["app"]["page_type"] = "html"; - context.var["app"]["page_title"] = first(config["menu"][context.var["app"]["route"]["l_path"].to_string()]["title"].to_string(), config["site"]["default_page_title"].to_string(), "Home"); - context.var["app"]["embed_mode"].set_bool(context.get["embed"] != ""); - - if(context.get["theme"] != "" && context.get["theme"] == requested_theme) - { - set_cookie("app_theme", requested_theme, time() + (86400 * 180)); - context.cookies["app_theme"] = requested_theme; - } - - session_start(); - AppUser(context).is_signed_in(); - - app_register_css(context.cfg.get_by_path("theme/path").to_string() + "css/style.css", context); - app_register_css("themes/common/fontawesome/css/all.min.css", context); - app_register_js("js/u-query.js", context); - app_register_js("js/morphdom.js", context); - app_register_js("js/site.js", context); -} diff --git a/site/info/uce-starter/lib/user.class.h b/site/info/uce-starter/lib/user.class.h deleted file mode 100644 index 6932641..0000000 --- a/site/info/uce-starter/lib/user.class.h +++ /dev/null @@ -1,186 +0,0 @@ -#pragma once - -struct AppUser -{ - - Request& context; - - explicit AppUser(Request& request) - : context(request) - { - } - - static String session_key() - { - return("app_user_id"); - } - - static String normalize_email(String email) - { - return(to_lower(trim(email))); - } - - static String hash_id(String raw) - { - raw = normalize_email(raw); - return(gen_sha1("uce-app:" + raw).substr(0, 12)); - } - - String root_path() - { - return(first(context.cfg.get_by_path("filebase/path").to_string(), "/tmp/uce-app-data")); - } - - String dir(String email) - { - String bucket = hash_id(email); - return(path_join(root_path(), "users/" + bucket.substr(0, 2) + "/" + bucket)); - } - - String file_name(String email) - { - return(path_join(dir(email), "account.json")); - } - - static String password_hash(String password, String salt) - { - String hash = "uce-app:" + password + ":" + salt; - for(s32 i = 0; i < 2048; i++) - hash = gen_sha1(hash + ":" + std::to_string(i)); - return(hash); - } - - static DTree read_json_file(String file_name) - { - DTree result; - if(!file_exists(file_name)) - return(result); - String raw = trim(file_get_contents(file_name)); - if(raw == "") - return(result); - return(json_decode(raw)); - } - - static bool write_json_file(String file_name, DTree data) - { - mkdir(dirname(file_name)); - return(file_put_contents(file_name, json_encode(data))); - } - - DTree load(String email) - { - DTree user = read_json_file(file_name(email)); - if(user.get_type_name() != "array") - return(DTree()); - user["id"] = normalize_email(email); - return(user); - } - - DTree create(String email, String password) - { - DTree result; - email = normalize_email(email); - password = trim(password); - result["message"] = ""; - result["result"].set_bool(false); - - if(email == "" || password == "") - { - result["message"] = "email_and_password_required"; - return(result); - } - if(email.find("@") == String::npos) - { - result["message"] = "invalid_email"; - return(result); - } - - DTree existing = load(email); - if(existing.get_type_name() == "array" && existing["email"].to_string() != "") - { - result["message"] = "user_exists"; - return(result); - } - - 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; - user["email"] = email; - user["salt"] = salt; - user["password_hash"] = password_hash(password, salt); - user["created"] = std::to_string((u64)time()); - DTree role; - role = "user"; - user["roles"].push(role); - - write_json_file(file_name(email), user); - user["id"] = email; - result["result"].set_bool(true); - result["id"] = email; - result["profile"] = user; - return(result); - } - - DTree sign_in(String email, String password) - { - DTree result; - result["result"].set_bool(false); - email = normalize_email(email); - password = trim(password); - - DTree user = load(email); - if(user.get_type_name() != "array" || user["email"].to_string() == "") - { - result["message"] = "no_such_user"; - return(result); - } - if(user["password_hash"].to_string() == "") - { - result["message"] = "no_password_set"; - return(result); - } - - String expected = password_hash(password, user["salt"].to_string()); - if(expected != user["password_hash"].to_string()) - { - result["message"] = "invalid_password"; - return(result); - } - - session_start(); - context.session[session_key()] = email; - context.var["app"]["current_user"] = user; - result["result"].set_bool(true); - result["profile"] = user; - return(result); - } - - bool is_signed_in() - { - if(context.var["app"]["current_user"]["email"].to_string() != "") - return(true); - String user_id = context.session[session_key()]; - if(user_id == "") - return(false); - DTree user = load(user_id); - if(user["email"].to_string() == "") - { - context.session.erase(session_key()); - return(false); - } - context.var["app"]["current_user"] = user; - return(true); - } - - DTree current() - { - if(is_signed_in()) - return(context.var["app"]["current_user"]); - return(DTree()); - } - - void logout() - { - context.session.erase(session_key()); - context.var["app"]["current_user"].clear(); - } -}; diff --git a/site/info/uce-starter/themes/common/css/gauges.css b/site/info/uce-starter/themes/common/css/gauges.css deleted file mode 100644 index 1c465da..0000000 --- a/site/info/uce-starter/themes/common/css/gauges.css +++ /dev/null @@ -1,348 +0,0 @@ -.gauge-demo-row { - display: flex; - gap: 1rem; - flex-wrap: wrap; - align-items: stretch; - margin-bottom: 1.5rem; -} - -.gauge-control-panel { - flex: 1 1 18rem; - min-width: 16rem; - padding: 1rem; - border: 1px solid var(--border); - border-radius: var(--radius); - background: var(--surface); - box-shadow: var(--shadow-sm); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); -} - -.gauge-control-panel h4 { - margin: 0 0 0.75rem; - color: var(--text-primary); -} - -.gauge-slider-group { - display: grid; - gap: 0.35rem; - margin-bottom: 0.9rem; -} - -.gauge-slider-group label { - color: var(--text-secondary); - font-weight: 600; - font-size: 0.92rem; -} - -.gauge-slider-group input[type="range"] { - width: 100%; - accent-color: var(--primary); -} - -.gauge-set, -.arcgauge-set { - flex: 1 1 24rem; - min-width: 20rem; - padding: 1rem; - border: 1px solid var(--border); - border-radius: var(--radius); - background: var(--surface); - box-shadow: var(--shadow-sm); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); -} - -.gauge-set-header, -.arcgauge-set-header { - margin-bottom: 1rem; -} - -.gauge-set-header h3, -.arcgauge-set-header h3 { - margin: 0 0 0.3rem; - color: var(--text-primary); -} - -.gauge-set-header p, -.arcgauge-set-header p { - margin: 0; - color: var(--text-secondary); -} - -.gauge-card, -.arcgauge-card { - display: flex; - flex-direction: column; - padding: 0.85rem; - border: 1px solid var(--border); - border-radius: var(--radius); - background: var(--surface-elevated, var(--surface)); - box-shadow: var(--shadow-sm); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - position: relative; - overflow: hidden; -} - -.gauge-card::before, -.arcgauge-card::before { - content: ''; - position: absolute; - inset: 0 0 auto 0; - height: 1px; - background: linear-gradient(90deg, transparent, var(--primary), var(--accent), transparent); - opacity: 0.5; -} - -.gauge-metric-label { - color: var(--text-secondary); - font-size: 0.78rem; - font-weight: 700; - letter-spacing: 0.08em; - text-transform: uppercase; -} - -.gauge-metric-value { - color: var(--text-primary); - font-size: 1.1rem; - font-weight: 700; - font-family: var(--font-mono, ui-monospace, monospace); - letter-spacing: -0.03em; -} - -.gauge-metric-meta { - color: var(--text-muted); - font-size: 0.84rem; - font-family: var(--font-mono, ui-monospace, monospace); -} - -.progressbar-set-horizontal, -.progressbar-set-vertical { - align-self: stretch; -} - -.progressbar-grid-horizontal { - display: grid; - gap: 0.85rem; -} - -.progressbar-grid-vertical { - display: grid; - gap: 0.85rem; - grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); - align-items: stretch; -} - -.progressbar-card-head { - display: flex; - align-items: baseline; - justify-content: space-between; - gap: 0.75rem; - margin-bottom: 0.7rem; -} - -.progressbar-card-horizontal { - gap: 0.7rem; -} - -.progressbar-card-vertical { - align-items: center; - justify-content: flex-end; - text-align: center; - gap: 0.7rem; -} - -.progressbar-label { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.progressbar-background { - position: relative; - overflow: hidden; - border: 1px solid color-mix(in srgb, var(--border) 70%, transparent 30%); - background: color-mix(in srgb, var(--bg-color) 72%, var(--surface) 28%); - display: flex; - box-shadow: inset 0 1px 0 rgba(255,255,255,0.04); -} - -.progressbar-background-horizontal { - height: 0.9rem; - border-radius: 999px; -} - -.progressbar-background-vertical { - height: var(--progressbar-height, 240px); - width: 100%; - max-width: 4rem; - margin: 0 auto; - border-radius: 1.2rem; - justify-content: flex-end; - padding: 0.35rem; - flex-direction: column; -} - - -.progressbar-bar { - transition: all 0.35s ease; - box-shadow: inset 0 0 0 1px rgba(255,255,255,0.12), 0 0 24px color-mix(in srgb, currentColor 28%, transparent 72%); -} - -.progressbar-background-horizontal .progressbar-bar { - height: 100%; - border-radius: 999px; -} - -.progressbar-background-vertical .progressbar-bar { - width: 100%; - border-radius: 0.95rem; -} - -.progressbar-marker { - position: absolute; - z-index: 10; - opacity: 0.72; - background: var(--text-color, var(--text-primary, #333)); - box-shadow: 0 0 0 1px rgba(255,255,255,0.16); -} - -.progressbar-marker:hover { - opacity: 1; -} - -.progressbar-background-horizontal .progressbar-marker { - height: 100%; - top: 0; - width: 3px; - transform: translateX(-50%); -} - -.progressbar-background-vertical .progressbar-marker { - width: 100%; - left: 0; - height: 3px; - transform: translateY(50%); -} - -.needlegauge-svg .needle { - transition: all 0.3s ease; -} - -.progressbar-meta { - margin-top: 0.1rem; -} - -.needlegauge-grid { - display: grid; - gap: 0.85rem; - grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); -} - -.needlegauge-card { - align-items: center; - text-align: center; - gap: 0.55rem; -} - -.needlegauge-label-head { - align-self: flex-start; -} - -.needlegauge-visual { - width: 100%; - display: flex; - justify-content: center; - align-items: center; -} - -.needlegauge-svg { - max-width: 100%; - overflow: visible; -} - - -.needlegauge-svg .ticks line { - opacity: 0.8; -} - -.needlegauge-svg .ticks text { - font-family: var(--font-mono, ui-monospace, monospace); - fill: var(--text-muted); -} - -.needlegauge-info { - display: flex; - flex-direction: column; - align-items: center; - gap: 0.2rem; -} - -.arcgauge-label { - margin-bottom: 0.35rem; -} - -.arcgauge-svg { - width: 130px; - height: 72px; - margin: 0.1rem 0 0.35rem; - overflow: visible; -} - -.arcgauge-track { - stroke: color-mix(in srgb, var(--border) 70%, transparent 30%); -} - -.arcgauge-arc-dyn { - transition: stroke-dasharray 0.6s ease, stroke 0.6s ease; -} - -.arcgauge-watermark { - stroke-width: 1.5; - stroke-linecap: round; -} - -.arcgauge-watermark-lo { - stroke: var(--primary); -} - -.arcgauge-watermark-hi { - stroke: var(--accent); -} - -.arcgauge-value { - fill: var(--text-primary); - font-size: 17px; - font-weight: 700; - font-family: var(--font-mono, ui-monospace, monospace); -} - -.arcgauge-caption { - fill: var(--text-muted); - font-size: 7px; - letter-spacing: 1.5px; - font-family: var(--font-sans, system-ui, sans-serif); -} - -.arcgauge-meta { - width: 100%; - text-align: center; -} - -.arcgauge-grid { - display: grid; - gap: 0.85rem; - grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); -} - -.arcgauge-card { - align-items: center; - text-align: center; -} - -@media (max-width: 768px) { - .gauge-demo-row { - flex-direction: column; - } -} \ No newline at end of file diff --git a/site/info/uce-starter/themes/common/css/workspace.css b/site/info/uce-starter/themes/common/css/workspace.css deleted file mode 100644 index b0575cb..0000000 --- a/site/info/uce-starter/themes/common/css/workspace.css +++ /dev/null @@ -1,522 +0,0 @@ -.ws-app { - --ws-sidebar-width: 280px; - --ws-frame-bg: var(--surface); - --ws-sidebar-bg: color-mix(in srgb, var(--bg-secondary) 80%, var(--surface) 20%); - --ws-main-bg: var(--surface); - --ws-surface-alt: color-mix(in srgb, var(--bg-secondary) 72%, var(--surface) 28%); - --ws-shadow: var(--shadow-md); - display: flex; - width: 100%; - min-height: min(76vh, 900px); - overflow: hidden; - position: relative; - background: var(--ws-frame-bg); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - box-shadow: var(--ws-shadow); -} - -.ws-sidebar { - width: var(--ws-sidebar-width); - flex-shrink: 0; - display: flex; - flex-direction: column; - min-height: 0; - background: var(--ws-sidebar-bg); - border-right: 1px solid var(--border); - position: relative; - z-index: 2; -} - -.ws-main { - flex: 1; - min-width: 0; - min-height: 0; - display: flex; - flex-direction: column; - background: var(--ws-main-bg); - padding: 0; -} - -.ws-sidebar-top, -.ws-panel-header, -.ws-section-head { - display: flex; - align-items: center; - justify-content: space-between; - gap: 0.75rem; -} - -.ws-sidebar-top { - padding: 0.9rem; - border-bottom: 1px solid var(--border); - flex-shrink: 0; - flex-direction: column; - align-items: stretch; - background: color-mix(in srgb, var(--surface) 78%, var(--bg-secondary) 22%); -} - -.ws-search-wrap { - position: relative; -} - -.ws-search-icon { - position: absolute; - left: 0.7rem; - top: 50%; - transform: translateY(-50%); - color: var(--text-muted); - font-size: 0.8rem; - pointer-events: none; -} - -.ws-search-input { - width: 100%; - min-height: 36px; - padding: 0 0.8rem 0 2rem; - border: 1px solid var(--border); - border-radius: var(--radius); - background: var(--bg-secondary); - font-size: 0.9rem; - color: var(--text-primary); -} - -.ws-search-input:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 20%, transparent 80%); -} - -.ws-panel-title-group, -.ws-header-actions { - display: flex; - align-items: center; - gap: 0.7rem; -} - -.ws-panel-title-group { - flex-direction: column; - align-items: flex-start; -} - -.ws-panel-title-group h2, -.ws-section-head h3, -.ws-empty-state h2 { - margin: 0; -} - -.ws-subtitle { - margin: 0; - color: var(--text-secondary); - font-size: 0.92rem; -} - -.ws-sidebar-overlay { - display: none; -} - -.ws-mobile-bar { - display: none; - align-items: center; - gap: 0.7rem; - padding: 0.9rem 1rem; - border-bottom: 1px solid var(--border); - background: color-mix(in srgb, var(--surface) 92%, var(--bg-secondary) 8%); - position: sticky; - top: 0; - z-index: 1; -} - -.ws-mobile-title { - font-size: 1rem; - font-weight: 700; - color: var(--text-primary); -} - -.ws-empty-state { - min-height: 320px; - display: grid; - place-items: center; - align-content: center; - gap: 0.75rem; - text-align: center; - padding: 2rem; - max-width: 40rem; - margin: auto; -} - -.ws-empty-state p { - max-width: 32rem; - color: var(--text-secondary); - margin: 0; -} - -.ws-empty-icon { - width: 64px; - height: 64px; - display: grid; - place-items: center; - border-radius: var(--radius); - background: linear-gradient(135deg, var(--primary), var(--accent)); - color: #fff; - font-size: 24px; - box-shadow: var(--shadow-sm); -} - -.ws-panel { - min-height: 0; - display: flex; - flex-direction: column; - padding: 1.1rem 1.25rem; - gap: 1rem; -} - -.ws-section { - display: flex; - flex-direction: column; - gap: 0.8rem; - padding: 1rem; - border: 1px solid var(--border); - border-radius: var(--radius); - background: var(--ws-surface-alt); -} - -.ws-section + .ws-section { - margin-top: 0.25rem; -} - -.ws-icon-btn { - min-width: 34px; - height: 34px; - padding: 0 0.75rem; - border: 1px solid var(--border); - border-radius: var(--radius-sm); - display: inline-flex; - align-items: center; - justify-content: center; - gap: 0.4rem; - flex-shrink: 0; - background: var(--bg-secondary); - color: var(--text-secondary); - cursor: pointer; - transition: background 0.2s ease, color 0.2s ease, transform 0.2s ease, border-color 0.2s ease; - text-decoration: none; -} - -.ws-icon-btn:hover { - background: var(--surface-hover); - border-color: var(--border-hover); - color: var(--text-primary); - text-decoration: none; -} - -.ws-icon-btn:active { - transform: translateY(1px); -} - -.ws-primary-btn, -.ws-sidebar-action-btn { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 0.55rem; - width: 100%; - min-height: 38px; - padding: 0.55rem 0.85rem; - border: none; - border-radius: var(--radius-sm); - background: var(--primary); - color: #fff; - font-size: 0.92rem; - font-weight: 700; - cursor: pointer; - transition: background 0.2s ease, transform 0.2s ease; -} - -.ws-primary-btn:hover, -.ws-sidebar-action-btn:hover { - background: var(--primary-dark); - text-decoration: none; - color: #fff; -} - -.ws-primary-btn:active, -.ws-sidebar-action-btn:active { - transform: translateY(1px); -} - -.ws-list-state { - padding: 1rem; - color: var(--text-secondary); - font-size: 0.86rem; - text-align: center; - display: flex; - align-items: center; - justify-content: center; - gap: 0.45rem; - border-top: 1px solid var(--border); -} - -.ws-nav-group-label { - padding: 0.7rem 0.95rem 0.35rem; - font-size: 0.72rem; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.06em; - color: var(--text-muted); - user-select: none; -} - -.ws-nav-list { - display: flex; - flex-direction: column; - padding: 0.3rem 0.4rem 0.9rem; - gap: 0.2rem; - overflow: auto; - min-height: 0; - flex: 1; -} - -.ws-nav-item { - display: block; - padding: 0 0.2rem; - text-decoration: none; - color: inherit; -} - -.ws-nav-item-inner { - display: flex; - align-items: center; - gap: 0.55rem; - width: 100%; - padding: 0.58rem 0.65rem; - border-radius: var(--radius-sm); - min-width: 0; - transition: background 0.2s ease, border-color 0.2s ease, padding-left 0.2s ease; - border-left: 3px solid transparent; -} - -.ws-nav-item:hover .ws-nav-item-inner { - background: color-mix(in srgb, var(--surface-hover) 85%, transparent 15%); -} - -.ws-nav-item.active .ws-nav-item-inner, -.ws-nav-item.is-active .ws-nav-item-inner { - background: color-mix(in srgb, var(--primary) 12%, transparent 88%); - border-left-color: var(--primary); - padding-left: calc(0.65rem - 3px); -} - -.ws-nav-icon { - flex-shrink: 0; - width: 16px; - text-align: center; - color: var(--text-muted); - font-size: 0.8rem; -} - -.ws-nav-item.active .ws-nav-icon, -.ws-nav-item.is-active .ws-nav-icon { - color: var(--primary); -} - -.ws-nav-item-text { - flex: 1; - min-width: 0; - display: flex; - align-items: center; - gap: 0.45rem; - overflow: hidden; -} - -.ws-nav-title { - flex: 1; - min-width: 0; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - font-size: 0.9rem; - color: var(--text-primary); - line-height: 1.3; -} - -.ws-nav-item.active .ws-nav-title, -.ws-nav-item.is-active .ws-nav-title { - font-weight: 700; - color: var(--primary-dark); -} - -.ws-nav-meta { - flex-shrink: 0; - font-size: 0.72rem; - color: var(--text-muted); - transition: opacity 0.2s ease; -} - -.ws-status-pill { - display: inline-flex; - align-items: center; - justify-content: center; - min-height: 24px; - padding: 0.2rem 0.6rem; - border-radius: 999px; - border: 1px solid transparent; - font-size: 0.76rem; - font-weight: 700; - letter-spacing: 0.01em; - white-space: nowrap; -} - -.ws-status-pill-neutral { - background: color-mix(in srgb, var(--text-muted) 16%, transparent 84%); - border-color: color-mix(in srgb, var(--text-muted) 28%, transparent 72%); - color: var(--text-secondary); -} - -.ws-status-pill-success { - background: var(--success-bg); - border-color: var(--success-border); - color: var(--success-text); -} - -.ws-status-pill-warn { - background: var(--warning-bg); - border-color: var(--warning-border); - color: var(--warning-text); -} - -.ws-status-pill-danger { - background: var(--error-bg); - border-color: var(--error-border); - color: var(--error-text); -} - -.ws-status-pill-info { - background: var(--info-bg); - border-color: var(--info-border); - color: var(--info-text); -} - -.ws-stat-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); - gap: 0.85rem; -} - -.ws-stat-card { - padding: 0.9rem 1rem; - border: 1px solid var(--border); - border-radius: var(--radius); - background: var(--bg-secondary); - display: flex; - flex-direction: column; - gap: 0.35rem; -} - -.ws-stat-card-label { - font-size: 0.78rem; - text-transform: uppercase; - letter-spacing: 0.05em; - font-weight: 700; - color: var(--text-secondary); -} - -.ws-stat-card-value { - font-size: 1.45rem; - font-weight: 700; - line-height: 1.1; - font-variant-numeric: tabular-nums; -} - -.ws-stat-card-meta, -.ws-section-copy, -.ws-inline-note, -.ws-detail-copy { - margin: 0; - color: var(--text-secondary); -} - -.ws-detail-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); - gap: 0.85rem; -} - -.ws-detail-card { - padding: 0.9rem 1rem; - border: 1px solid var(--border); - border-radius: var(--radius); - background: color-mix(in srgb, var(--bg-secondary) 85%, var(--surface) 15%); - min-height: 100%; -} - -.ws-detail-card h4 { - margin: 0 0 0.35rem; - font-size: 0.95rem; -} - -.ws-detail-card p { - margin: 0; - color: var(--text-secondary); - font-size: 0.9rem; -} - -.ws-demo-sidebar-copy { - padding: 0 1rem 1rem; - font-size: 0.84rem; - color: var(--text-secondary); -} - -.ws-demo-sidebar-copy p { - margin: 0; -} - -@media (max-width: 860px) { - .ws-app { - display: block; - min-height: 72vh; - } - - .ws-sidebar { - position: absolute; - left: 0; - top: 0; - bottom: 0; - width: min(88vw, max(var(--ws-sidebar-width), 320px)); - transform: translateX(-100%); - transition: transform 160ms ease; - box-shadow: var(--shadow-lg); - z-index: 10; - } - - .ws-sidebar.is-open { - transform: translateX(0); - } - - .ws-sidebar-overlay.is-open { - display: block; - position: absolute; - inset: 0; - background: rgba(15, 23, 42, 0.38); - z-index: 5; - } - - .ws-mobile-bar { - display: flex; - } - - .ws-panel { - padding: 1rem; - } - - .ws-stat-grid, - .ws-detail-grid { - grid-template-columns: 1fr; - } - - .ws-section-head, - .ws-panel-header { - align-items: flex-start; - flex-direction: column; - } -} \ No newline at end of file diff --git a/site/info/uce-starter/themes/common/fontawesome/LICENSE.txt b/site/info/uce-starter/themes/common/fontawesome/LICENSE.txt deleted file mode 100755 index f31bef9..0000000 --- a/site/info/uce-starter/themes/common/fontawesome/LICENSE.txt +++ /dev/null @@ -1,34 +0,0 @@ -Font Awesome Free License -------------------------- - -Font Awesome Free is free, open source, and GPL friendly. You can use it for -commercial projects, open source projects, or really almost whatever you want. -Full Font Awesome Free license: https://fontawesome.com/license/free. - -# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/) -In the Font Awesome Free download, the CC BY 4.0 license applies to all icons -packaged as SVG and JS file types. - -# Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL) -In the Font Awesome Free download, the SIL OFL license applies to all icons -packaged as web and desktop font files. - -# Code: MIT License (https://opensource.org/licenses/MIT) -In the Font Awesome Free download, the MIT license applies to all non-font and -non-icon files. - -# Attribution -Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font -Awesome Free files already contain embedded comments with sufficient -attribution, so you shouldn't need to do anything additional when using these -files normally. - -We've kept attribution comments terse, so we ask that you do not actively work -to remove them from files, especially code. They're a great way for folks to -learn about Font Awesome. - -# Brand Icons -All brand icons are trademarks of their respective owners. The use of these -trademarks does not indicate endorsement of the trademark holder by Font -Awesome, nor vice versa. **Please do not use brand logos for any purpose except -to represent the company, product, or service to which they refer.** diff --git a/site/info/uce-starter/themes/common/fontawesome/css/all.min.css b/site/info/uce-starter/themes/common/fontawesome/css/all.min.css deleted file mode 100755 index 0f922d8..0000000 --- a/site/info/uce-starter/themes/common/fontawesome/css/all.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Font Awesome Free 5.10.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - */ -.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-wizard:before{content:"\f6e8"}.fa-haykal:before{content:"\f666"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;font-display:auto;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;font-display:auto;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;font-display:auto;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} \ No newline at end of file diff --git a/site/info/uce-starter/themes/common/fontawesome/css/fontawesome.min.css b/site/info/uce-starter/themes/common/fontawesome/css/fontawesome.min.css deleted file mode 100755 index ab52c55..0000000 --- a/site/info/uce-starter/themes/common/fontawesome/css/fontawesome.min.css +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * Font Awesome Free 5.10.0 by @fontawesome - https://fontawesome.com - * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) - */ -.fa,.fab,.fad,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s linear infinite;animation:fa-spin 2s linear infinite}.fa-pulse{-webkit-animation:fa-spin 1s steps(8) infinite;animation:fa-spin 1s steps(8) infinite}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";-webkit-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";-webkit-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";-webkit-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";-webkit-transform:scaleX(-1);transform:scaleX(-1)}.fa-flip-vertical{-webkit-transform:scaleY(-1);transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{-webkit-transform:scale(-1);transform:scale(-1)}:root .fa-flip-both,:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-airbnb:before{content:"\f834"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-bacon:before{content:"\f7e5"}.fa-balance-scale:before{content:"\f24e"}.fa-balance-scale-left:before{content:"\f515"}.fa-balance-scale-right:before{content:"\f516"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-battle-net:before{content:"\f835"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-biking:before{content:"\f84a"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-medical:before{content:"\f7e6"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bootstrap:before{content:"\f836"}.fa-border-all:before{content:"\f84c"}.fa-border-none:before{content:"\f850"}.fa-border-style:before{content:"\f853"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-bread-slice:before{content:"\f7ec"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-buffer:before{content:"\f837"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-cheese:before{content:"\f7ef"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-chromecast:before{content:"\f838"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clinic-medical:before{content:"\f7f2"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-medical:before{content:"\f7f5"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-cotton-bureau:before{content:"\f89e"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-crutch:before{content:"\f7f7"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-egg:before{content:"\f7fb"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-evernote:before{content:"\f839"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fan:before{content:"\f863"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-alt:before{content:"\f841"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hamburger:before{content:"\f805"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-middle-finger:before{content:"\f806"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hanukiah:before{content:"\f6e6"}.fa-hard-hat:before{content:"\f807"}.fa-hashtag:before{content:"\f292"}.fa-hat-wizard:before{content:"\f6e8"}.fa-haykal:before{content:"\f666"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotdog:before{content:"\f80f"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-ice-cream:before{content:"\f810"}.fa-icicles:before{content:"\f7ad"}.fa-icons:before{content:"\f86d"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itch-io:before{content:"\f83a"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laptop-medical:before{content:"\f812"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-pager:before{content:"\f815"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-carry:before{content:"\f4ce"}.fa-pepper-hot:before{content:"\f816"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-alt:before{content:"\f879"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-square-alt:before{content:"\f87b"}.fa-phone-volume:before{content:"\f2a0"}.fa-photo-video:before{content:"\f87c"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-pizza-slice:before{content:"\f818"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-remove-format:before{content:"\f87d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-salesforce:before{content:"\f83b"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-down-alt:before{content:"\f881"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-alpha-up-alt:before{content:"\f882"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-down-alt:before{content:"\f884"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-amount-up-alt:before{content:"\f885"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-down-alt:before{content:"\f886"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-numeric-up-alt:before{content:"\f887"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-speaker-deck:before{content:"\f83c"}.fa-spell-check:before{content:"\f891"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stackpath:before{content:"\f842"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-symfony:before{content:"\f83d"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-trash-restore:before{content:"\f829"}.fa-trash-restore-alt:before{content:"\f82a"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-nurse:before{content:"\f82f"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-voicemail:before{content:"\f897"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-wave-square:before{content:"\f83e"}.fa-waze:before{content:"\f83f"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yammer:before{content:"\f840"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto} \ No newline at end of file diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.eot b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.eot deleted file mode 100755 index 30a2784..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.eot and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.svg b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.svg deleted file mode 100755 index 47bb690..0000000 --- a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.svg +++ /dev/null @@ -1,3451 +0,0 @@ - - - - - -Created by FontForge 20190112 at Mon Jul 29 09:54:22 2019 - By Robert Madole -Copyright (c) Font Awesome - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.ttf b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.ttf deleted file mode 100755 index a7ab4d4..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.woff b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.woff deleted file mode 100755 index ec5b613..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.woff and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.woff2 b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.woff2 deleted file mode 100755 index df11cea..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-brands-400.woff2 and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.eot b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.eot deleted file mode 100755 index b5440c9..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.eot and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.svg b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.svg deleted file mode 100755 index 5ec81a8..0000000 --- a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.svg +++ /dev/null @@ -1,803 +0,0 @@ - - - - - -Created by FontForge 20190112 at Mon Jul 29 09:54:22 2019 - By Robert Madole -Copyright (c) Font Awesome - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.ttf b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.ttf deleted file mode 100755 index 87693a8..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.woff b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.woff deleted file mode 100755 index 917bf73..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.woff and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.woff2 b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.woff2 deleted file mode 100755 index 0f10115..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-regular-400.woff2 and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.eot b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.eot deleted file mode 100755 index 305fc64..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.eot and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.svg b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.svg deleted file mode 100755 index eb47f6a..0000000 --- a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.svg +++ /dev/null @@ -1,4649 +0,0 @@ - - - - - -Created by FontForge 20190112 at Mon Jul 29 09:54:21 2019 - By Robert Madole -Copyright (c) Font Awesome - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.ttf b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.ttf deleted file mode 100755 index 8fb4d53..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.woff b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.woff deleted file mode 100755 index 69f4474..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.woff and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.woff2 b/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.woff2 deleted file mode 100755 index 20e4ce2..0000000 Binary files a/site/info/uce-starter/themes/common/fontawesome/webfonts/fa-solid-900.woff2 and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/b612/b612-bold-italic.ttf b/site/info/uce-starter/themes/common/fonts/b612/b612-bold-italic.ttf deleted file mode 100755 index 049965e..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/b612/b612-bold-italic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/b612/b612-bold.ttf b/site/info/uce-starter/themes/common/fonts/b612/b612-bold.ttf deleted file mode 100755 index 3c92e2e..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/b612/b612-bold.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/b612/b612-italic.ttf b/site/info/uce-starter/themes/common/fonts/b612/b612-italic.ttf deleted file mode 100755 index 01ec3c5..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/b612/b612-italic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/b612/b612-mono-bold-italic.ttf b/site/info/uce-starter/themes/common/fonts/b612/b612-mono-bold-italic.ttf deleted file mode 100755 index ec2a812..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/b612/b612-mono-bold-italic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/b612/b612-mono-bold.ttf b/site/info/uce-starter/themes/common/fonts/b612/b612-mono-bold.ttf deleted file mode 100755 index fb26114..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/b612/b612-mono-bold.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/b612/b612-mono-italic.ttf b/site/info/uce-starter/themes/common/fonts/b612/b612-mono-italic.ttf deleted file mode 100755 index af20348..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/b612/b612-mono-italic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/b612/b612-mono-regular.ttf b/site/info/uce-starter/themes/common/fonts/b612/b612-mono-regular.ttf deleted file mode 100755 index aaac636..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/b612/b612-mono-regular.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/b612/b612-regular.ttf b/site/info/uce-starter/themes/common/fonts/b612/b612-regular.ttf deleted file mode 100755 index c685a23..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/b612/b612-regular.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Black.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Black.ttf deleted file mode 100755 index 4c0ee56..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Black.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-BlackItalic.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-BlackItalic.ttf deleted file mode 100755 index fa51576..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-BlackItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Bold.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Bold.ttf deleted file mode 100755 index 3cb9269..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Bold.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-BoldItalic.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-BoldItalic.ttf deleted file mode 100755 index 010ed45..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-BoldItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-ExtraLight.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-ExtraLight.ttf deleted file mode 100755 index 8550ed9..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-ExtraLight.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-ExtraLightItalic.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-ExtraLightItalic.ttf deleted file mode 100755 index 2e93072..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-ExtraLightItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Italic.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Italic.ttf deleted file mode 100755 index 592caec..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Italic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Light.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Light.ttf deleted file mode 100755 index 1f42361..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Light.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-LightItalic.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-LightItalic.ttf deleted file mode 100755 index ff1769f..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-LightItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Medium.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Medium.ttf deleted file mode 100755 index dcd2c27..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Medium.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-MediumItalic.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-MediumItalic.ttf deleted file mode 100755 index 18da8c6..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-MediumItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Regular.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Regular.ttf deleted file mode 100755 index 0af4e38..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Regular.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Thin.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Thin.ttf deleted file mode 100755 index 09cc053..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-Thin.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-ThinItalic.ttf b/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-ThinItalic.ttf deleted file mode 100755 index e25a540..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/input-sans/InputSansCondensed-ThinItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/press-start-2p/OFL.txt b/site/info/uce-starter/themes/common/fonts/press-start-2p/OFL.txt deleted file mode 100644 index 22796df..0000000 --- a/site/info/uce-starter/themes/common/fonts/press-start-2p/OFL.txt +++ /dev/null @@ -1,93 +0,0 @@ -Copyright 2012 The Press Start 2P Project Authors (cody@zone38.net), with Reserved Font Name "Press Start 2P". - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/site/info/uce-starter/themes/common/fonts/press-start-2p/press-start-2p-regular.ttf b/site/info/uce-starter/themes/common/fonts/press-start-2p/press-start-2p-regular.ttf deleted file mode 100644 index 39adf42..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/press-start-2p/press-start-2p-regular.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Black.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Black.ttf deleted file mode 100755 index 689fe5c..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Black.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-BlackItalic.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-BlackItalic.ttf deleted file mode 100755 index 0b4e0ee..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-BlackItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Bold.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Bold.ttf deleted file mode 100755 index d3f01ad..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Bold.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-BoldItalic.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-BoldItalic.ttf deleted file mode 100755 index 41cc1e7..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-BoldItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Italic.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Italic.ttf deleted file mode 100755 index 6a1cee5..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Italic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Light.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Light.ttf deleted file mode 100755 index 219063a..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Light.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-LightItalic.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-LightItalic.ttf deleted file mode 100755 index 0e81e87..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-LightItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Medium.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Medium.ttf deleted file mode 100755 index 1a7f3b0..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Medium.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-MediumItalic.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-MediumItalic.ttf deleted file mode 100755 index 0030295..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-MediumItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Regular.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Regular.ttf deleted file mode 100755 index 2c97eea..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Regular.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Thin.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Thin.ttf deleted file mode 100755 index b74a4fd..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-Thin.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-ThinItalic.ttf b/site/info/uce-starter/themes/common/fonts/roboto/Roboto-ThinItalic.ttf deleted file mode 100755 index dd0ddb8..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/Roboto-ThinItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Bold.ttf b/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Bold.ttf deleted file mode 100755 index fc28868..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Bold.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-BoldItalic.ttf b/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-BoldItalic.ttf deleted file mode 100755 index e1a648f..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-BoldItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Italic.ttf b/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Italic.ttf deleted file mode 100755 index 97ff9f1..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Italic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Light.ttf b/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Light.ttf deleted file mode 100755 index 2dae31e..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Light.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-LightItalic.ttf b/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-LightItalic.ttf deleted file mode 100755 index da108d3..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-LightItalic.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Regular.ttf b/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Regular.ttf deleted file mode 100755 index c2304c1..0000000 Binary files a/site/info/uce-starter/themes/common/fonts/roboto/RobotoCondensed-Regular.ttf and /dev/null differ diff --git a/site/info/uce-starter/themes/common/page.blank.uce b/site/info/uce-starter/themes/common/page.blank.uce deleted file mode 100644 index 40d48f7..0000000 --- a/site/info/uce-starter/themes/common/page.blank.uce +++ /dev/null @@ -1,7 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - print(starter_page_main_html(context)); -} diff --git a/site/info/uce-starter/themes/common/page.json.uce b/site/info/uce-starter/themes/common/page.json.uce deleted file mode 100644 index 975a1a8..0000000 --- a/site/info/uce-starter/themes/common/page.json.uce +++ /dev/null @@ -1,14 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - context.header["Content-Type"] = "application/json"; - context.header["Cache-Control"] = "no-cache, no-store, must-revalidate"; - if(context.call["json"].get_type_name() == "array") - print(json_encode(context.call["json"])); - else if(context.var["starter"]["json"].get_type_name() == "array") - print(json_encode(context.var["starter"]["json"])); - else - print(starter_page_main_html(context)); -} diff --git a/site/info/uce-starter/themes/dark/css/style.css b/site/info/uce-starter/themes/dark/css/style.css deleted file mode 100755 index 0b45533..0000000 --- a/site/info/uce-starter/themes/dark/css/style.css +++ /dev/null @@ -1,516 +0,0 @@ -:root { - /* Dark theme color palette */ - --bg-color: #0f172a; - --bg-secondary: #1e293b; - --bg-gradient: linear-gradient(135deg, #1e3a8a 0%, #3730a3 100%); - --surface: #1e293b; - --surface-elevated: #334155; - --surface-hover: #475569; - --primary: #60a5fa; - --primary-dark: #3b82f6; - --primary-light: #93c5fd; - --secondary: #a78bfa; - --accent: #22d3ee; - --text-primary: #f1f5f9; - --text-secondary: #cbd5e1; - --text-muted: #94a3b8; - --border: #334155; - --border-hover: #475569; - --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3); - --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3); - --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3); - --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.4); - --radius: 8px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-xl: 16px; - --radius-sm: 4px; - - /* Dark theme specific variables */ - --glass-bg: rgba(30, 41, 59, 0.8); - --glass-border: rgba(148, 163, 184, 0.1); - --overlay: rgba(0, 0, 0, 0.6); - --success: #10b981; - --success-bg: rgba(16, 185, 129, 0.1); - --success-border: rgba(16, 185, 129, 0.3); - --success-text: #10b981; - --warning: #f59e0b; - --warning-bg: rgba(245, 158, 11, 0.1); - --warning-border: rgba(245, 158, 11, 0.3); - --warning-text: #f59e0b; - --error: #ef4444; - --error-bg: rgba(239, 68, 68, 0.1); - --error-border: rgba(239, 68, 68, 0.3); - --error-text: #ef4444; - --info: #3b82f6; - --info-bg: rgba(59, 130, 246, 0.1); - --info-border: rgba(59, 130, 246, 0.3); - --info-text: #3b82f6; -} - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -html { - font-size: 16px; - scroll-behavior: smooth; -} - -body { - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - font-size: 1rem; - font-weight: 400; - line-height: 1.6; - color: var(--text-primary); - background: var(--bg-color); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -/* Links */ -a { - color: var(--primary); - text-decoration: none; - transition: all 0.2s ease; -} - -a:hover { - color: var(--primary-light); - text-decoration: underline; -} - -/* Modern Navigation */ -nav { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 1000; - background: var(--glass-bg); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - border-bottom: 1px solid var(--border); - padding: 0 1rem; - display: flex; - align-items: center; - box-shadow: var(--shadow-sm); - transition: all 0.3s ease; -} - -nav > a, -.nav-menu a { - display: inline-flex; - align-items: center; - padding: 0.625rem 1rem; - color: var(--text-primary); - text-decoration: none; - font-weight: 500; - transition: all 0.2s ease; - position: relative; - border-radius: var(--radius); - margin: 0.35rem 0.15rem; -} - -nav > a:first-child, -.nav-menu > a:first-child { - font-weight: 700; - color: var(--primary); - padding-left: 1.25rem; - padding-right: 1.25rem; -} - -nav > a:hover, -.nav-menu a:hover { - background: var(--surface-hover); - color: var(--primary); - text-decoration: none; -} - -nav > a::after, -.nav-menu a::after { - content: ''; - position: absolute; - bottom: 0; - left: 50%; - width: 0; - height: 2px; - background: var(--primary); - transition: all 0.3s ease; - transform: translateX(-50%); -} - -nav > a:hover::after, -.nav-menu a:hover::after { - width: 60%; -} - -/* Account area inside the nav */ -.nav-menu { - display: flex; - align-items: center; - gap: 0.25rem; -} - -.nav-account { - margin-left: auto; - display: flex; - align-items: center; - gap: 0.5rem; -} - -nav.nav-scrolled { - background: rgba(30, 41, 59, 0.95) !important; - backdrop-filter: blur(20px) !important; - -webkit-backdrop-filter: blur(20px) !important; - box-shadow: var(--shadow-md) !important; -} - -#content { - margin-top: 5rem; - min-height: calc(100vh - 10rem); - padding: 2rem 1rem; - max-width: 1200px; - margin-left: auto; - margin-right: auto; -} - -/* Typography */ -h1, h2, h3, h4, h5, h6 { - font-weight: 700; - line-height: 1.2; - margin-bottom: 1rem; - color: var(--text-primary); -} - -h1 { - font-size: 2rem; - position: relative; - padding-bottom: 0.75rem; - margin-bottom: 1.25rem; -} - -h1::before { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 60px; - height: 3px; - background: var(--bg-gradient); - border-radius: 3px; -} - -h2 { - font-size: 2rem; -} - -h3 { - font-size: 1.5rem; -} - -/* Modern Cards/Blocks */ -#content > div:not(.ws-app), .block, .card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - padding: 1.75rem; - margin-bottom: 1.5rem; - box-shadow: var(--shadow-sm); - transition: border-color 0.25s ease, box-shadow 0.25s ease; -} - -#content > div:not(.ws-app):hover, .block:hover, .card:hover { - box-shadow: var(--shadow-md); - border-color: var(--border-hover); -} - -/* Modern Forms */ -form { - max-width: 600px; - margin: 0 auto; -} - -form > div { - display: flex; - flex-direction: column; - margin-bottom: 1.5rem; - gap: 0.5rem; -} - -form > div > label { - font-weight: 500; - color: var(--text-secondary); - font-size: 0.875rem; - text-transform: uppercase; - letter-spacing: 0.05em; - transition: all 0.2s ease; -} - -form > div > input, form > div > textarea, form > div > select { - padding: 0.75rem 1rem; - border: 2px solid var(--border); - border-radius: var(--radius); - background: var(--bg-secondary); - color: var(--text-primary); - font-size: 1rem; - transition: all 0.2s ease; -} - -form > div > input:focus, form > div > textarea:focus, form > div > select:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.2); - background: var(--surface); -} - -/* Enhanced form validation states */ -form > div > input.valid, form > div > textarea.valid { - border-color: var(--success); - box-shadow: 0 0 0 3px var(--success-bg); -} - -form > div > input.invalid, form > div > textarea.invalid { - border-color: var(--error); - box-shadow: 0 0 0 3px var(--error-bg); -} - -/* Floating label effect */ -form > div.focused > label { - transform: translateY(-0.5rem) scale(0.85); - color: var(--primary); -} - -/* Modern Buttons */ -button, .btn, form > div > input[type=submit], input[type="submit"] { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0.75rem 1.5rem; - background: var(--primary); - color: var(--bg-color); - border: none; - border-radius: var(--radius); - font-weight: 500; - font-size: 1rem; - cursor: pointer; - transition: all 0.2s ease; - text-decoration: none; - position: relative; - overflow: hidden; -} - -button:hover, .btn:hover, form > div > input[type=submit]:hover, input[type="submit"]:hover { - background: var(--primary-dark); - transform: translateY(-1px); - box-shadow: var(--shadow-lg); -} - -button:active, .btn:active { - transform: translateY(0); -} - -input[type="range"] { - width: 100%; - height: 6px; - background: var(--bg-color); - outline: none; - border-radius: 3px; - -webkit-appearance: none; - appearance: none; -} - -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - appearance: none; - width: 20px; - height: 20px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - box-shadow: var(--shadow-sm); -} - -input[type="range"]::-moz-range-thumb { - width: 20px; - height: 20px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - border: none; - box-shadow: var(--shadow-sm); -} - -/* Button variants */ -.btn-secondary { - background: var(--secondary); -} - -.btn-secondary:hover { - background: #8b5cf6; -} - -.btn-outline { - background: transparent; - color: var(--primary); - border: 2px solid var(--primary); -} - -.btn-outline:hover { - background: var(--primary); - color: var(--bg-color); -} - -.btn-large { - padding: 1rem 2rem; - font-size: 1.125rem; -} - -/* Utility Classes */ -.banner { - padding: 1rem 1.5rem; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - margin-bottom: 1rem; -} - -.banner.success { - background: var(--success-bg); - border-color: var(--success-border); - color: var(--success); -} - -.banner.warning { - background: var(--warning-bg); - border-color: var(--warning-border); - color: var(--warning); -} - -.banner.error { - background: var(--error-bg); - border-color: var(--error-border); - color: var(--error); -} - -.error { - color: var(--error); -} - -/* Footer */ -footer { - text-align: center; - color: var(--text-muted); - padding: 2rem 1rem; - margin-top: 4rem; - border-top: 1px solid var(--border); - background: var(--surface); -} - -/* Mobile Responsive Design */ -@media (max-width: 768px) { - nav { - padding: 0 0.5rem; - overflow-x: auto; - white-space: nowrap; - scrollbar-width: none; - -ms-overflow-style: none; - } - - nav::-webkit-scrollbar { - display: none; - } - - nav > a { - padding: 0.75rem 1rem; - margin: 0.25rem 0.125rem; - font-size: 0.875rem; - display: inline-flex; - flex-shrink: 0; - } - - #content { - margin-top: 4rem; - padding: 1rem 0.5rem; - } - - h1 { - font-size: 1.875rem; - padding: 1.5rem; - } - - #content > div, .block, .card { - padding: 1.5rem; - margin-bottom: 1rem; - } - - form > div { - margin-bottom: 1rem; - } - - button, .btn { - padding: 0.875rem 1.25rem; - font-size: 0.9rem; - } -} - -@media (max-width: 480px) { - nav > a { - padding: 0.5rem 0.75rem; - font-size: 0.8rem; - } - - #content { - padding: 1rem 0.25rem; - } - - h1 { - font-size: 1.5rem; - padding: 1rem; - } - - #content > div, .block, .card { - padding: 1rem; - border-radius: var(--radius); - } -} - -/* Smooth scrolling and improved animations */ -* { - scroll-behavior: smooth; -} - -/* Loading animation for better perceived performance */ -@keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.5; } -} - -.loading { - animation: pulse 2s ease-in-out infinite; -} - -/* Focus states for accessibility */ -button:focus, .btn:focus, input:focus, textarea:focus, select:focus { - outline: 2px solid var(--primary); - outline-offset: 2px; -} - -/* Print styles */ -@media print { - nav, footer, .cta-section { - display: none; - } - - #content { - margin-top: 0; - } - - * { - background: white !important; - color: black !important; - box-shadow: none !important; - } -} diff --git a/site/info/uce-starter/themes/dark/icon.png b/site/info/uce-starter/themes/dark/icon.png deleted file mode 100755 index 8a42581..0000000 Binary files a/site/info/uce-starter/themes/dark/icon.png and /dev/null differ diff --git a/site/info/uce-starter/themes/dark/page.html.uce b/site/info/uce-starter/themes/dark/page.html.uce deleted file mode 100644 index 8645bb0..0000000 --- a/site/info/uce-starter/themes/dark/page.html.uce +++ /dev/null @@ -1,31 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - - DTree nav_props; - nav_props["account_wrapper_class"] = "nav-account nav-menu"; - - DTree footer_props; - footer_props["embed_mode"].set_bool(embed_mode); - - <> - - "> - - - - > - - -
> - -
- - - - -} diff --git a/site/info/uce-starter/themes/light/css/style.css b/site/info/uce-starter/themes/light/css/style.css deleted file mode 100755 index b872b44..0000000 --- a/site/info/uce-starter/themes/light/css/style.css +++ /dev/null @@ -1,540 +0,0 @@ -:root { - /* Light theme color palette */ - --bg-color: #f8fafc; - --bg-secondary: #ffffff; - --bg-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); - --surface: #ffffff; - --surface-elevated: #ffffff; - --surface-hover: #f1f5f9; - --primary: #3b82f6; - --primary-dark: #1d4ed8; - --primary-light: #93c5fd; - --secondary: #8b5cf6; - --accent: #06b6d4; - --text-primary: #1e293b; - --text-secondary: #64748b; - --text-muted: #94a3b8; - --border: #e2e8f0; - --border-hover: #cbd5e1; - --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); - --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); - --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); - --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); - --radius: 8px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-xl: 16px; - --radius-sm: 4px; - - /* Light theme specific variables */ - --glass-bg: rgba(255, 255, 255, 0.95); - --glass-border: rgba(0, 0, 0, 0.1); - --overlay: rgba(0, 0, 0, 0.3); - --success: #10b981; - --success-bg: #dcfce7; - --success-border: #16a34a; - --success-text: #065f46; - --warning: #f59e0b; - --warning-bg: #fef3c7; - --warning-border: #d97706; - --warning-text: #92400e; - --error: #ef4444; - --error-bg: #fee2e2; - --error-border: #dc2626; - --error-text: #991b1b; - --info: #3b82f6; - --info-bg: #dbeafe; - --info-border: #2563eb; - --info-text: #1e40af; -} - -* { - margin: 0; - padding: 0; - box-sizing: border-box; -} - -html { - font-size: 16px; - scroll-behavior: smooth; -} - -body { - font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - font-size: 1rem; - font-weight: 400; - line-height: 1.6; - color: var(--text-primary); - background: var(--bg-color); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -/* Links */ -a { - color: var(--primary); - text-decoration: none; - transition: all 0.2s ease; -} - -a:hover { - color: var(--primary-dark); - text-decoration: underline; -} - -/* Modern Navigation */ -nav { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 1000; - background: var(--glass-bg); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - border-bottom: 1px solid var(--border); - padding: 0 1rem; - display: flex; - align-items: center; - box-shadow: var(--shadow-sm); - transition: all 0.3s ease; -} - -nav > a, -.nav-menu a { - display: inline-flex; - align-items: center; - padding: 0.625rem 1rem; - color: var(--text-primary); - text-decoration: none; - font-weight: 500; - transition: all 0.2s ease; - position: relative; - border-radius: var(--radius); - margin: 0.35rem 0.15rem; -} - -nav > a:first-child, -.nav-menu > a:first-child { - font-weight: 700; - color: var(--primary); - padding-left: 1.25rem; - padding-right: 1.25rem; -} - -nav > a:hover, -.nav-menu a:hover { - background: var(--surface-hover); - color: var(--primary); - text-decoration: none; -} - -nav > a::after, -.nav-menu a::after { - content: ''; - position: absolute; - bottom: 0; - left: 50%; - width: 0; - height: 2px; - background: var(--primary); - transition: all 0.3s ease; - transform: translateX(-50%); -} - -nav > a:hover::after, -.nav-menu a:hover::after { - width: 60%; -} - -/* Account area inside the nav */ -.nav-menu { - display: flex; - align-items: center; - gap: 0.25rem; -} - -.nav-account { - margin-left: auto; - display: flex; - align-items: center; - gap: 0.5rem; -} - -.nav-account .account-name { - color: var(--text-secondary); - font-weight: 500; - margin-right: 0.5rem; - font-size: 0.95rem; -} - -.nav-account a { - display: inline-flex; - align-items: center; - padding: 0.5rem 0.75rem; - border-radius: var(--radius); - color: var(--text-primary); - text-decoration: none; -} - -.nav-account a:hover { - background: var(--surface-hover); - color: var(--primary-dark); -} - -/* Navigation scroll state */ -nav.nav-scrolled { - background: rgba(255, 255, 255, 0.98) !important; - backdrop-filter: blur(20px) !important; - -webkit-backdrop-filter: blur(20px) !important; - box-shadow: var(--shadow-md) !important; -} - -/* Main Content Area */ -#content { - margin-top: 5rem; - min-height: calc(100vh - 10rem); - padding: 2rem 1rem; - max-width: 1200px; - margin-left: auto; - margin-right: auto; -} - -/* Typography */ -h1, h2, h3, h4, h5, h6 { - font-weight: 700; - line-height: 1.2; - margin-bottom: 1rem; - color: var(--text-primary); -} - -h1 { - font-size: 2.5rem; - background: var(--surface); - padding: 1.75rem 2rem; - border-radius: var(--radius-lg); - box-shadow: var(--shadow-sm); - border: 1px solid var(--border); - position: relative; - overflow: hidden; -} - -h1::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - height: 3px; - background: var(--bg-gradient); -} - -h2 { - font-size: 2rem; -} - -h3 { - font-size: 1.5rem; -} - -/* Modern Cards/Blocks */ -#content > div:not(.ws-app), .block, .card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - padding: 1.75rem; - margin-bottom: 1.5rem; - box-shadow: var(--shadow-sm); - transition: border-color 0.25s ease, box-shadow 0.25s ease; -} - -#content > div:not(.ws-app):hover, .block:hover, .card:hover { - box-shadow: var(--shadow-md); - border-color: var(--border-hover); -} - -/* Modern Forms */ -form { - max-width: 600px; - margin: 0 auto; -} - -form > div { - display: flex; - flex-direction: column; - margin-bottom: 1.5rem; - gap: 0.5rem; -} - -form > div > label { - font-weight: 500; - color: var(--text-secondary); - font-size: 0.875rem; - text-transform: uppercase; - letter-spacing: 0.05em; - transition: all 0.2s ease; -} - -form > div > input, form > div > textarea, form > div > select { - padding: 0.75rem 1rem; - border: 2px solid var(--border); - border-radius: var(--radius); - background: var(--surface); - color: var(--text-primary); - font-size: 1rem; - transition: all 0.2s ease; -} - -form > div > input:focus, form > div > textarea:focus, form > div > select:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); -} - -/* Enhanced form validation states */ -form > div > input.valid, form > div > textarea.valid { - border-color: var(--success); - box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1); -} - -form > div > input.invalid, form > div > textarea.invalid { - border-color: var(--error); - box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1); -} - -/* Floating label effect */ -form > div.focused > label { - transform: translateY(-0.5rem) scale(0.85); - color: var(--primary); -} - -/* Modern Buttons */ -button, .btn, form > div > input[type=submit], input[type="submit"] { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0.75rem 1.5rem; - background: var(--primary); - color: white; - border: none; - border-radius: var(--radius); - font-weight: 500; - font-size: 1rem; - cursor: pointer; - transition: all 0.2s ease; - text-decoration: none; - position: relative; - overflow: hidden; -} - -button:hover, .btn:hover, form > div > input[type=submit]:hover, input[type="submit"]:hover { - background: var(--primary-dark); - transform: translateY(-1px); - box-shadow: var(--shadow-lg); -} - -button:active, .btn:active { - transform: translateY(0); -} - -/* Button variants */ -.btn-secondary { - background: var(--secondary); -} - -.btn-secondary:hover { - background: #7c3aed; -} - -.btn-outline { - background: transparent; - color: var(--primary); - border: 2px solid var(--primary); -} - -.btn-outline:hover { - background: var(--primary); - color: white; -} - -.btn-large { - padding: 1rem 2rem; - font-size: 1.125rem; -} - -input[type="range"] { - width: 100%; - height: 6px; - background: var(--bg-color); - outline: none; - border-radius: 3px; - -webkit-appearance: none; - appearance: none; -} - -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - appearance: none; - width: 20px; - height: 20px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - box-shadow: var(--shadow-sm); -} - -input[type="range"]::-moz-range-thumb { - width: 20px; - height: 20px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - border: none; - box-shadow: var(--shadow-sm); -} - -/* Utility Classes */ -.banner { - padding: 1rem 1.5rem; - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - margin-bottom: 1rem; -} - -.banner.success { - background: var(--success-bg); - border-color: var(--success-border); - color: var(--success); -} - -.banner.warning { - background: var(--warning-bg); - border-color: var(--warning-border); - color: var(--warning); -} - -.banner.error { - background: var(--error-bg); - border-color: var(--error-border); - color: var(--error); -} - -.error { - color: var(--error); -} - -/* Footer */ -footer { - text-align: center; - color: var(--text-muted); - padding: 2rem 1rem; - margin-top: 4rem; - border-top: 1px solid var(--border); - background: var(--surface); -} - -/* Mobile Responsive Design */ -@media (max-width: 768px) { - nav { - padding: 0 0.5rem; - overflow-x: auto; - white-space: nowrap; - scrollbar-width: none; - -ms-overflow-style: none; - } - - nav::-webkit-scrollbar { - display: none; - } - - nav > a { - padding: 0.75rem 1rem; - margin: 0.25rem 0.125rem; - font-size: 0.875rem; - display: inline-flex; - flex-shrink: 0; - } - - #content { - margin-top: 4rem; - padding: 1rem 0.5rem; - } - - h1 { - font-size: 1.875rem; - padding: 1.5rem; - } - - #content > div, .block, .card { - padding: 1.5rem; - margin-bottom: 1rem; - } - - form > div { - margin-bottom: 1rem; - } - - button, .btn { - padding: 0.875rem 1.25rem; - font-size: 0.9rem; - } -} - -@media (max-width: 480px) { - nav > a { - padding: 0.5rem 0.75rem; - font-size: 0.8rem; - } - - #content { - padding: 1rem 0.25rem; - } - - h1 { - font-size: 1.5rem; - padding: 1rem; - } - - #content > div, .block, .card { - padding: 1rem; - border-radius: var(--radius); - } -} - -/* Smooth scrolling and improved animations */ -* { - scroll-behavior: smooth; -} - -/* Loading animation for better perceived performance */ -@keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.5; } -} - -.loading { - animation: pulse 2s ease-in-out infinite; -} - -/* Focus states for accessibility */ -button:focus, .btn:focus, input:focus, textarea:focus, select:focus { - outline: 2px solid var(--primary); - outline-offset: 2px; -} - -/* Print styles */ -@media print { - nav, footer, .cta-section { - display: none; - } - - #content { - margin-top: 0; - } - - * { - background: white !important; - color: black !important; - box-shadow: none !important; - } -} diff --git a/site/info/uce-starter/themes/light/icon.png b/site/info/uce-starter/themes/light/icon.png deleted file mode 100755 index 8a42581..0000000 Binary files a/site/info/uce-starter/themes/light/icon.png and /dev/null differ diff --git a/site/info/uce-starter/themes/light/img/favicon.png b/site/info/uce-starter/themes/light/img/favicon.png deleted file mode 100755 index 6653d41..0000000 Binary files a/site/info/uce-starter/themes/light/img/favicon.png and /dev/null differ diff --git a/site/info/uce-starter/themes/light/page.html.uce b/site/info/uce-starter/themes/light/page.html.uce deleted file mode 100644 index 495d3e0..0000000 --- a/site/info/uce-starter/themes/light/page.html.uce +++ /dev/null @@ -1,28 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - - DTree footer_props; - footer_props["embed_mode"].set_bool(embed_mode); - - <> - - "> - - - - > - - -
> - -
- - - - -} diff --git a/site/info/uce-starter/themes/localfirst/css/style.css b/site/info/uce-starter/themes/localfirst/css/style.css deleted file mode 100644 index 088ce45..0000000 --- a/site/info/uce-starter/themes/localfirst/css/style.css +++ /dev/null @@ -1,382 +0,0 @@ -@font-face { - font-family: 'B612'; - src: url('../../common/fonts/b612/b612-regular.ttf') format('truetype'); - font-style: normal; - font-weight: 400; - font-display: swap; -} -@font-face { - font-family: 'B612'; - src: url('../../common/fonts/b612/b612-bold.ttf') format('truetype'); - font-style: normal; - font-weight: 700; - font-display: swap; -} -@font-face { - font-family: 'B612 Mono'; - src: url('../../common/fonts/b612/b612-mono-regular.ttf') format('truetype'); - font-style: normal; - font-weight: 400; - font-display: swap; -} -@font-face { - font-family: 'B612 Mono'; - src: url('../../common/fonts/b612/b612-mono-bold.ttf') format('truetype'); - font-style: normal; - font-weight: 700; - font-display: swap; -} - -@keyframes pulse-glow { - 0%, 100% { opacity: 1; box-shadow: 0 0 8px var(--accent), 0 0 16px rgba(255,107,26,0.28); } - 50% { opacity: 0.6; box-shadow: 0 0 4px var(--accent), 0 0 8px rgba(255,107,26,0.16); } -} - -:root { - --brand-cyan: #00b7f9; - --brand-cyan-soft: #58d2ff; - --brand-cyan-bright: #b6eeff; - --brand-cyan-deep: #0088bb; - --brand-orange: #ff6b1a; - --brand-orange-soft: #ff9f6a; - --brand-orange-bright: #ffd0b3; - --bg-color: #020913; - --bg-secondary: #07131f; - --surface: rgba(7, 19, 31, 0.9); - --surface-elevated: rgba(10, 28, 43, 0.96); - --surface-hover: rgba(0, 183, 249, 0.08); - --card: rgba(7, 19, 31, 0.84); - --text-primary: var(--brand-cyan-soft); - --text-secondary: rgba(139, 222, 255, 0.82); - --text-muted: rgba(101, 161, 188, 0.78); - --primary: var(--brand-cyan); - --primary-light: rgba(0, 183, 249, 0.18); - --primary-dark: var(--brand-cyan-deep); - --secondary: var(--brand-cyan-soft); - --accent: var(--brand-orange); - --success: #34d399; - --success-bg: rgba(52, 211, 153, 0.1); - --success-border: rgba(52, 211, 153, 0.3); - --success-text: #7ef0bb; - --warning: var(--brand-orange); - --warning-bg: rgba(255, 107, 26, 0.12); - --warning-border: rgba(255, 107, 26, 0.32); - --warning-text: #ffc29f; - --error: #fb7185; - --error-bg: rgba(251, 113, 133, 0.12); - --error-border: rgba(251, 113, 133, 0.3); - --error-text: #fecdd3; - --info: var(--brand-cyan); - --info-bg: rgba(0, 183, 249, 0.1); - --info-border: rgba(0, 183, 249, 0.28); - --info-text: var(--brand-cyan-bright); - --border: rgba(67, 149, 182, 0.22); - --border-hover: rgba(98, 205, 246, 0.36); - --shadow-sm: 0 8px 20px rgba(0, 0, 0, 0.18); - --shadow-md: 0 14px 32px rgba(0, 0, 0, 0.24); - --shadow-lg: 0 18px 38px rgba(0, 0, 0, 0.28); - --shadow-xl: 0 22px 48px rgba(0, 0, 0, 0.34); - --radius: 10px; - --radius-sm: 6px; - --radius-md: 10px; - --radius-lg: 16px; - --radius-xl: 20px; - --font-sans: 'B612', 'Segoe UI', sans-serif; - --font-mono: 'B612 Mono', ui-monospace, monospace; -} - -* { box-sizing: border-box; margin: 0; } -html { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } -body { - font-family: var(--font-sans); - font-size: 14px; - background: var(--bg-color); - color: var(--text-primary); - min-height: 100vh; -} -body::before { - content: ''; - position: fixed; - inset: 0; - background: - radial-gradient(ellipse 80% 60% at 10% 0%, rgba(0,183,249,0.12) 0%, transparent 60%), - radial-gradient(ellipse 60% 50% at 90% 100%, rgba(255,107,26,0.08) 0%, transparent 60%); - pointer-events: none; - z-index: 0; -} -a { color: var(--accent); text-decoration: none; } -a:hover { text-decoration: underline; } - -body.admin-page { overflow: hidden; height: 100vh; } -.admin-shell { display: flex; height: 100vh; overflow: hidden; position: relative; z-index: 1; } -.admin-nav { - width: 210px; - flex-shrink: 0; - background: - linear-gradient(180deg, rgba(5, 16, 26, 0.98), rgba(2, 10, 18, 0.98)), - linear-gradient(180deg, rgba(0, 174, 240, 0.06), rgba(255, 107, 26, 0.04)); - border-right: 1px solid var(--border); - display: flex; - flex-direction: column; - overflow-y: auto; - padding: 0 0 16px; -} -.admin-nav-header { - border-bottom: 1px solid var(--border); - margin-bottom: 10px; - display: flex; - align-items: center; - gap: 9px; - padding: 10px 10px 12px; -} -.admin-nav-title { display: block; width: 100%; } -.admin-nav-logo-img { display: block; width: 100%; height: auto; } -.admin-nav-item { - display: block; - padding: 9px 16px 9px 14px; - text-decoration: none; - color: var(--text-secondary); - font-size: 12px; - text-transform: uppercase; - letter-spacing: 1px; - font-weight: 600; - transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease; - border-left: 3px solid transparent; -} -.admin-nav-item:hover { - color: var(--brand-cyan-bright); - background: linear-gradient(90deg, rgba(0, 174, 240, 0.12), rgba(255, 107, 26, 0.03)); - text-decoration: none; -} -.admin-nav-item.active { - color: var(--accent); - border-left-color: var(--accent); - background: linear-gradient(90deg, rgba(255, 107, 26, 0.16), rgba(255, 107, 26, 0.04)); - box-shadow: inset 0 0 0 1px rgba(255, 107, 26, 0.08); -} - -.admin-main { - flex: 1; - min-width: 0; - position: relative; - display: flex; - flex-direction: column; -} - -.admin-toolbar { - position: fixed; - top: 16px; - right: 20px; - z-index: 40; - display: flex; - justify-content: flex-end; - pointer-events: none; -} - -.admin-account-card { - pointer-events: auto; - display: inline-flex; - align-items: center; - gap: 10px; - padding: 8px 12px; - border-radius: 999px; - border: 1px solid var(--border); - background: rgba(7, 19, 31, 0.78); - box-shadow: var(--shadow-sm); - backdrop-filter: blur(8px); - -webkit-backdrop-filter: blur(8px); -} -.admin-account-name { - color: var(--brand-cyan-bright); - font-size: 12px; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.08em; -} -.admin-account-links { - display: inline-flex; - gap: 10px; - align-items: center; -} -.admin-account-links a { - color: var(--accent); - font-size: 12px; - text-transform: uppercase; - letter-spacing: 0.08em; - font-weight: 700; -} - -.admin-content { - flex: 1; - overflow-y: auto; - padding: 16px 20px 28px; - position: relative; - min-width: 0; -} - -h1 { - font-size: 18px; - font-weight: 600; - letter-spacing: 1.4px; - text-transform: uppercase; - color: var(--brand-cyan-bright); - display: flex; - align-items: center; - gap: 10px; - margin: 0 0 14px; -} -h1::before { - content: ''; - display: inline-block; - width: 8px; - height: 8px; - background: var(--accent); - border-radius: 2px; - box-shadow: 0 0 8px var(--accent), 0 0 16px rgba(255,107,26,0.24); - animation: pulse-glow 2.5s ease-in-out infinite; -} -h2, h3, h4, h5, h6 { - color: var(--brand-cyan-bright); - margin: 0 0 10px; - text-transform: uppercase; - letter-spacing: 0.08em; -} -p { margin: 0 0 12px; color: var(--text-secondary); } - -.card, -.block, -.dashboard-panel, -#content > div:not(.ws-app):not(.demo-section) { - background: var(--card); - backdrop-filter: blur(16px); - -webkit-backdrop-filter: blur(16px); - border: 1px solid var(--border); - border-radius: var(--radius); - padding: 14px; - position: relative; - transition: border-color 0.25s ease, box-shadow 0.25s ease; - margin-bottom: 14px; -} -.card::before, -.block::before, -.dashboard-panel::before, -#content > div:not(.ws-app):not(.demo-section)::before { - content: ''; - position: absolute; - top: 0; - left: 12px; - right: 12px; - height: 1px; - background: linear-gradient(90deg, transparent, var(--primary), var(--accent), transparent); - opacity: 0.55; -} -.card:hover, -.block:hover, -.dashboard-panel:hover, -#content > div:not(.ws-app):not(.demo-section):hover { - border-color: var(--border-hover); - box-shadow: var(--shadow-md); -} - -form { max-width: 760px; } -form > div { display: grid; gap: 6px; margin-bottom: 12px; } -label { - color: var(--text-muted); - font-size: 12px; - text-transform: uppercase; - letter-spacing: 0.08em; - font-weight: 700; -} -input, select, textarea { - width: 100%; - border: 1px solid var(--border); - border-radius: var(--radius); - background: rgba(3, 7, 18, 0.55); - color: var(--brand-cyan-bright); - padding: 10px 12px; - font: inherit; -} -textarea { min-height: 120px; } -input:focus, select:focus, textarea:focus { - outline: none; - border-color: var(--border-hover); - box-shadow: 0 0 0 3px rgba(0, 183, 249, 0.12); -} -button, .btn, input[type="submit"] { - border: 1px solid var(--border); - background: rgba(255, 107, 26, 0.12); - color: var(--brand-orange-bright); - border-radius: var(--radius); - padding: 10px 14px; - font: inherit; - font-weight: 700; - text-transform: uppercase; - letter-spacing: 0.08em; - cursor: pointer; - transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease; -} -button:hover, .btn:hover, input[type="submit"]:hover { - background: rgba(255, 107, 26, 0.18); - border-color: rgba(255, 107, 26, 0.42); - text-decoration: none; -} -button:active, .btn:active { transform: translateY(1px); } - -.banner { - border-radius: var(--radius); - padding: 10px 12px; - border: 1px solid var(--border); - background: rgba(0, 183, 249, 0.08); - color: var(--text-secondary); - margin-bottom: 12px; -} -.banner.success { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); } -.banner.warning { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning-text); } -.banner.error, .error { background: var(--error-bg); border-color: var(--error-border); color: var(--error-text); } - -table { - width: 100%; - border-collapse: collapse; - background: rgba(3, 7, 18, 0.42); - border: 1px solid var(--border); - border-radius: var(--radius); - overflow: hidden; -} -th, td { - padding: 10px 12px; - border-bottom: 1px solid var(--border); - text-align: left; - vertical-align: top; -} -th { - font-size: 12px; - letter-spacing: 0.08em; - text-transform: uppercase; - color: var(--text-muted); - background: rgba(0, 183, 249, 0.08); -} -tr:last-child td { border-bottom: none; } - -code, pre { font-family: var(--font-mono); } -pre { - padding: 12px; - background: rgba(3, 7, 18, 0.55); - border: 1px solid var(--border); - border-radius: var(--radius); - overflow: auto; -} - -@media (max-width: 980px) { - .admin-shell { flex-direction: column; height: auto; min-height: 100vh; } - .admin-nav { - width: 100%; - flex-direction: row; - overflow-x: auto; - padding-bottom: 0; - } - .admin-nav-header { min-width: 180px; margin-bottom: 0; border-bottom: 0; border-right: 1px solid var(--border); } - .admin-nav-item { white-space: nowrap; border-left: 0; border-bottom: 3px solid transparent; } - .admin-nav-item.active { border-bottom-color: var(--accent); border-left-color: transparent; } - .admin-toolbar { position: static; justify-content: flex-start; margin: 16px 20px 0; } - .admin-content { padding-top: 12px; } -} \ No newline at end of file diff --git a/site/info/uce-starter/themes/localfirst/icon.png b/site/info/uce-starter/themes/localfirst/icon.png deleted file mode 100644 index 22994d8..0000000 Binary files a/site/info/uce-starter/themes/localfirst/icon.png and /dev/null differ diff --git a/site/info/uce-starter/themes/localfirst/img/local_first_logo.png b/site/info/uce-starter/themes/localfirst/img/local_first_logo.png deleted file mode 100644 index 22994d8..0000000 Binary files a/site/info/uce-starter/themes/localfirst/img/local_first_logo.png and /dev/null differ diff --git a/site/info/uce-starter/themes/localfirst/page.html.uce b/site/info/uce-starter/themes/localfirst/page.html.uce deleted file mode 100644 index 5a7771c..0000000 --- a/site/info/uce-starter/themes/localfirst/page.html.uce +++ /dev/null @@ -1,54 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - String current_path = context.var["starter"]["route"]["l_path"].to_string(); - - DTree global_props; - global_props["cookie_consent"].set_bool(false); - - DTree account_props; - account_props["wrapper_class"] = "admin-account-card"; - account_props["links_wrapper_class"] = "admin-account-links"; - account_props["name_class"] = "admin-account-name"; - - <> - - "> - - - - "> - -
- -
- -
- -
- -
- -
-
-
- - - -} diff --git a/site/info/uce-starter/themes/portal-dark/css/style.css b/site/info/uce-starter/themes/portal-dark/css/style.css deleted file mode 100644 index 90001c3..0000000 --- a/site/info/uce-starter/themes/portal-dark/css/style.css +++ /dev/null @@ -1,313 +0,0 @@ -:root { - --bg-color: #0f172a; - --bg-secondary: #1e293b; - --surface: #1e293b; - --surface-elevated: #334155; - --surface-hover: #475569; - --primary: #60a5fa; - --primary-dark: #3b82f6; - --primary-light: #93c5fd; - --secondary: #a78bfa; - --accent: #22d3ee; - --text-primary: #f1f5f9; - --text-secondary: #cbd5e1; - --text-muted: #94a3b8; - --border: #334155; - --border-hover: #475569; - --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3); - --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.3); - --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.4), 0 4px 6px -2px rgba(0, 0, 0, 0.3); - --shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.5), 0 10px 10px -5px rgba(0, 0, 0, 0.4); - --radius: 8px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-xl: 16px; - --radius-sm: 4px; - --glass-bg: rgba(30, 41, 59, 0.8); - --success: #10b981; - --success-bg: rgba(16, 185, 129, 0.1); - --success-border: rgba(16, 185, 129, 0.3); - --success-text: #10b981; - --warning: #f59e0b; - --warning-bg: rgba(245, 158, 11, 0.1); - --warning-border: rgba(245, 158, 11, 0.3); - --warning-text: #f59e0b; - --error: #ef4444; - --error-bg: rgba(239, 68, 68, 0.1); - --error-border: rgba(239, 68, 68, 0.3); - --error-text: #ef4444; - --info: #3b82f6; - --info-bg: rgba(59, 130, 246, 0.1); - --info-border: rgba(59, 130, 246, 0.3); - --info-text: #3b82f6; - --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - --font-mono: 'SFMono-Regular', Consolas, monospace; -} - -* { margin: 0; padding: 0; box-sizing: border-box; } -html { font-size: 16px; scroll-behavior: smooth; } -body { - font-family: var(--font-sans); - font-size: 1rem; - line-height: 1.6; - color: var(--text-primary); - background: var(--bg-color); - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -a { color: var(--primary); text-decoration: none; transition: all 0.2s ease; } -a:hover { color: var(--primary-light); text-decoration: underline; } - -::selection { - background: rgba(96, 165, 250, 0.3); - color: var(--text-primary); -} - -body::before { - content: ''; - position: fixed; - inset: 0; - background: - radial-gradient(ellipse 80% 50% at 20% -10%, rgba(96, 165, 250, 0.05) 0%, transparent 60%), - radial-gradient(ellipse 60% 40% at 85% 110%, rgba(34, 211, 238, 0.04) 0%, transparent 50%); - pointer-events: none; - z-index: 0; -} - -nav { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 1000; - background: var(--glass-bg); - backdrop-filter: blur(20px); - -webkit-backdrop-filter: blur(20px); - border-bottom: 1px solid var(--border); - padding: 0 1rem; - display: flex; - align-items: center; - box-shadow: var(--shadow-sm); - transition: all 0.3s ease; -} -nav::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 1px; - background: linear-gradient(90deg, transparent, var(--primary), var(--accent), transparent); - opacity: 0.3; -} - -.nav-menu { display: flex; align-items: center; gap: 0.25rem; } -.nav-menu a, -.nav-account a { - display: inline-flex; - align-items: center; - padding: 0.5rem 0.75rem; - border-radius: var(--radius); - color: var(--text-primary); - text-decoration: none; -} -.nav-menu > a:first-child { - font-weight: 700; - color: var(--primary); - padding: 1rem 1.5rem; - margin: 0.5rem 0.25rem; -} -.nav-menu a:hover, -.nav-account a:hover { - background: var(--surface-hover); - color: var(--primary); -} -.nav-account { - margin-left: auto; - display: flex; - align-items: center; - gap: 0.5rem; -} -.nav-account .account-name { - color: var(--text-secondary); - font-weight: 500; - font-size: 0.95rem; - margin-right: 0.5rem; -} -.nav-account .nav-avatar, -.profile-avatar { - border-radius: 999px; - object-fit: cover; - border: 1px solid var(--border); -} -.nav-account .nav-avatar { width: 30px; height: 30px; } -.profile-avatar { width: 96px; height: 96px; } - -#content { - margin-top: 5rem; - min-height: calc(100vh - 10rem); - padding: 2rem 1rem; - max-width: 1200px; - margin-left: auto; - margin-right: auto; -} - -h1, h2, h3, h4, h5, h6 { - font-weight: 700; - line-height: 1.2; - margin-bottom: 1rem; - color: var(--text-primary); -} -h1 { - font-size: 2rem; - position: relative; - padding-bottom: 0.75rem; - margin-bottom: 1.25rem; -} -h1::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 60px; - height: 3px; - background: linear-gradient(90deg, var(--primary), var(--accent)); - border-radius: 3px; -} -h2 { font-size: 2rem; } -h3 { font-size: 1.5rem; } - -#content > div:not(.ws-app), .block, .card, .dashboard-panel { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - padding: 1.75rem; - margin-bottom: 1.5rem; - box-shadow: var(--shadow-sm); - transition: border-color 0.25s ease, box-shadow 0.25s ease; -} - -#content > div:not(.ws-app):hover, .block:hover, .card:hover, .dashboard-panel:hover { - box-shadow: var(--shadow-md); - border-color: var(--border-hover); -} - -form { max-width: 600px; margin: 0 auto; } -form > div { display: flex; flex-direction: column; margin-bottom: 1.5rem; gap: 0.5rem; } -label { font-weight: 500; color: var(--text-secondary); font-size: 0.875rem; text-transform: uppercase; letter-spacing: 0.05em; } -input, select, textarea { - width: 100%; - padding: 0.75rem 1rem; - border: 2px solid var(--border); - border-radius: var(--radius); - background: var(--bg-secondary); - color: var(--text-primary); - font-size: 1rem; - font-family: inherit; -} -textarea { min-height: 120px; } -input:focus, select:focus, textarea:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.2); - background: var(--surface); -} -button, .btn, input[type="submit"] { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0.75rem 1.5rem; - background: var(--primary); - color: var(--bg-color); - border: none; - border-radius: var(--radius); - font-weight: 600; - font-size: 1rem; - cursor: pointer; - transition: all 0.2s ease; -} -button:hover, .btn:hover, input[type="submit"]:hover { - background: var(--primary-dark); - transform: translateY(-1px); - box-shadow: var(--shadow-lg); - text-decoration: none; -} - -.banner { - border-radius: var(--radius); - padding: 0.8rem 1rem; - border: 1px solid var(--border); - margin-bottom: 1rem; - background: rgba(255,255,255,0.03); -} -.banner.success { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); } -.banner.warning { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning-text); } -.banner.error, .error { background: var(--error-bg); border-color: var(--error-border); color: var(--error-text); } - -table { - width: 100%; - border-collapse: collapse; - border: 1px solid var(--border); - background: rgba(255,255,255,0.02); - border-radius: var(--radius); - overflow: hidden; -} -th, td { padding: 0.8rem 0.9rem; border-bottom: 1px solid var(--border); text-align: left; } -th { background: var(--surface-elevated); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; } -tr:last-child td { border-bottom: none; } -tr:hover td { background: rgba(255,255,255,0.02); } -code, pre { font-family: var(--font-mono); } -pre { - padding: 1rem; - background: rgba(15, 23, 42, 0.55); - border: 1px solid var(--border); - border-radius: var(--radius); - overflow: auto; -} - -footer { - border-top: 1px solid var(--border); - padding: 1.25rem 1rem; - color: var(--text-muted); - font-size: 0.875rem; - background: rgba(15, 23, 42, 0.6); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); -} - -input[type="range"] { - width: 100%; - height: 6px; - background: var(--bg-secondary); - outline: none; - border: none; - border-radius: 999px; - -webkit-appearance: none; - appearance: none; -} -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - width: 18px; - height: 18px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - box-shadow: 0 0 6px rgba(96, 165, 250, 0.3); -} -input[type="range"]::-moz-range-thumb { - width: 18px; - height: 18px; - background: var(--primary); - cursor: pointer; - border-radius: 50%; - border: none; - box-shadow: 0 0 6px rgba(96, 165, 250, 0.3); -} - -@media (max-width: 860px) { - nav { flex-wrap: wrap; padding-bottom: 0.6rem; } - .nav-account { width: 100%; margin-left: 0; justify-content: flex-start; } - #content { margin-top: 7.5rem; padding: 1rem 0.75rem; } - #content > div:not(.ws-app), .block, .card, .dashboard-panel { padding: 1.25rem; margin-bottom: 1rem; } - h1 { font-size: 2rem; padding: 1.25rem; } -} \ No newline at end of file diff --git a/site/info/uce-starter/themes/portal-dark/icon.png b/site/info/uce-starter/themes/portal-dark/icon.png deleted file mode 100644 index 8a42581..0000000 Binary files a/site/info/uce-starter/themes/portal-dark/icon.png and /dev/null differ diff --git a/site/info/uce-starter/themes/portal-dark/page.html.uce b/site/info/uce-starter/themes/portal-dark/page.html.uce deleted file mode 100644 index 3f353a7..0000000 --- a/site/info/uce-starter/themes/portal-dark/page.html.uce +++ /dev/null @@ -1,31 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - - DTree nav_props; - nav_props["account_wrapper_class"] = "nav-account nav-menu"; - - DTree footer_props; - footer_props["embed_mode"].set_bool(embed_mode); - - <> - - "> - - - - "> - - -
> - -
- - - - -} diff --git a/site/info/uce-starter/themes/portal-light/css/style.css b/site/info/uce-starter/themes/portal-light/css/style.css deleted file mode 100644 index 141b15f..0000000 --- a/site/info/uce-starter/themes/portal-light/css/style.css +++ /dev/null @@ -1,392 +0,0 @@ -@font-face { - font-family: "B612"; - src: url("../../common/fonts/b612/b612-regular.ttf") format("truetype"); - font-style: normal; - font-weight: 400; - font-display: swap; -} -@font-face { - font-family: "B612"; - src: url("../../common/fonts/b612/b612-italic.ttf") format("truetype"); - font-style: italic; - font-weight: 400; - font-display: swap; -} -@font-face { - font-family: "B612"; - src: url("../../common/fonts/b612/b612-bold.ttf") format("truetype"); - font-style: normal; - font-weight: 700; - font-display: swap; -} -@font-face { - font-family: "B612 Mono"; - src: url("../../common/fonts/b612/b612-mono-regular.ttf") format("truetype"); - font-style: normal; - font-weight: 400; - font-display: swap; -} -@font-face { - font-family: "B612 Mono"; - src: url("../../common/fonts/b612/b612-mono-bold.ttf") format("truetype"); - font-style: normal; - font-weight: 700; - font-display: swap; -} - -:root { - --kg-blue: #0f68ad; - --kg-blue-dark: #0b4f85; - --kg-blue-light: #2d86ca; - --kg-bg: #e9e9ea; - --kg-surface: #ffffff; - --kg-border: rgba(0, 0, 0, 0.2); - --kg-text: #121417; - --kg-muted: #6c737b; - --kg-orange: #f08a00; - --kg-success: #149b2e; - --kg-danger: #e11818; - --topbar-height: 56px; - --bg-color: var(--kg-bg); - --bg-secondary: #ffffff; - --surface: var(--kg-surface); - --surface-elevated: #ffffff; - --surface-hover: #e8eef3; - --primary: var(--kg-blue); - --primary-dark: var(--kg-blue-dark); - --primary-light: var(--kg-blue-light); - --secondary: #596572; - --accent: var(--kg-orange); - --text-primary: var(--kg-text); - --text-secondary: #4b5560; - --text-muted: var(--kg-muted); - --border: var(--kg-border); - --border-hover: rgba(15, 104, 173, 0.3); - --success: var(--kg-success); - --success-bg: #e7f5ea; - --success-border: #86c88f; - --success-text: #0f6e22; - --warning: #c97a14; - --warning-bg: #fff4e4; - --warning-border: #f0c07b; - --warning-text: #92550a; - --error: var(--kg-danger); - --error-bg: #ffe7e7; - --error-border: #ea9999; - --error-text: #b80f0f; - --info: var(--primary); - --info-bg: #e8f2ff; - --info-border: #b9d4f3; - --info-text: #0b4f85; - --shadow-sm: 0 1px 2px rgba(18, 20, 23, 0.06); - --shadow-md: 0 8px 22px rgba(18, 20, 23, 0.06); - --shadow-lg: 0 16px 34px rgba(18, 20, 23, 0.1); - --shadow-xl: 0 20px 40px rgba(18, 20, 23, 0.14); - --radius: 8px; - --radius-sm: 6px; - --radius-md: 8px; - --radius-lg: 12px; - --radius-xl: 16px; - --font-sans: "B612", "Segoe UI", sans-serif; - --font-mono: "B612 Mono", "SFMono-Regular", Consolas, monospace; -} - -* { box-sizing: border-box; margin: 0; padding: 0; } -html, body { min-height: 100%; } -body { - font-family: var(--font-sans); - font-size: 14px; - line-height: 1.4; - color: var(--text-primary); - background: var(--bg-color); -} -a { color: var(--primary-dark); text-decoration: none; } -a:hover { text-decoration: underline; } - -nav { - position: fixed; - top: 0; - left: 0; - right: 0; - height: var(--topbar-height); - display: flex; - align-items: stretch; - background: var(--primary); - border-bottom: 1px solid var(--primary-dark); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.12); - z-index: 60; -} - -.nav-menu { - display: flex; - align-items: stretch; - overflow-x: auto; - white-space: nowrap; - flex: 1; -} - -.nav-menu > a { - display: inline-flex; - align-items: center; - padding: 0 0.9rem; - color: #fff; - border-right: 1px solid rgba(255, 255, 255, 0.16); - font-size: 14px; - font-weight: 700; - text-decoration: none; - background: transparent; -} - -.nav-menu > a:first-child { - font-size: 18px; - min-width: 250px; - background: rgba(0, 0, 0, 0.08); -} - -.nav-menu > a:hover, -.nav-menu > a:focus { - background: var(--primary-dark); - text-decoration: none; -} - -.nav-account { - display: flex; - align-items: center; - gap: 0.45rem; - padding: 0 0.7rem; - border-left: 1px solid rgba(255, 255, 255, 0.2); - background: rgba(0, 0, 0, 0.12); - flex-shrink: 0; -} - -.nav-account .account-name { - color: #d8f8df; - font-size: 14px; - font-weight: 700; -} - -.nav-account .nav-avatar, -.profile-avatar { - border-radius: 999px; - object-fit: cover; - border: 1px solid rgba(255, 255, 255, 0.4); -} - -.nav-account .nav-avatar { - width: 30px; - height: 30px; -} - -.profile-avatar { - width: 96px; - height: 96px; - border-color: var(--border); -} - -.nav-account a { - color: #fff; - font-size: 14px; - font-weight: 700; - padding: 0.22rem 0.5rem; - border-radius: 3px; -} - -.nav-account a:hover { - background: rgba(255, 255, 255, 0.16); - text-decoration: none; -} - -#content { - margin-top: var(--topbar-height); - padding: 1rem; - min-height: calc(100vh - var(--topbar-height)); -} - -#content > div:not(.ws-app), -.block, -.card, -.dashboard-panel { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - box-shadow: var(--shadow-sm); - padding: 1.25rem; - margin-bottom: 1rem; - transition: box-shadow 0.2s ease, border-color 0.2s ease; -} - -#content > div:not(.ws-app):hover, -.block:hover, -.card:hover, -.dashboard-panel:hover { - box-shadow: var(--shadow-md); - border-color: rgba(15, 104, 173, 0.2); -} - -h1, h2, h3, h4, h5, h6 { - font-weight: 700; - color: #252b31; - margin-bottom: 0.7rem; -} -h1 { font-size: 22px; padding-bottom: 0.5rem; border-bottom: 2px solid #d2d3d7; position: relative; } -h1::after { - content: ''; - position: absolute; - bottom: -2px; - left: 0; - width: 50px; - height: 2px; - background: var(--primary); - border-radius: 2px; -} -h2 { font-size: 18px; } -h3 { font-size: 16px; } -h4, h5, h6 { font-size: 14px; } - -p { margin: 0.4rem 0 0.85rem; } - -form { max-width: 780px; } -form > div { margin-bottom: 0.8rem; } -label { - display: block; - font-weight: 700; - font-size: 14px; - color: #3f464f; - margin-bottom: 0.3rem; -} -input, select, textarea { - width: 100%; - min-height: 36px; - padding: 0 0.7rem; - border: 1px solid #a8aaaf; - border-radius: 4px; - background: #fff; - color: var(--text-primary); - font-size: 14px; - font-family: inherit; -} -textarea { min-height: 100px; padding: 0.5rem 0.7rem; } -input:focus, select:focus, textarea:focus { - outline: none; - border-color: var(--primary-light); - box-shadow: 0 0 0 1px var(--primary-light); -} -button, .btn, input[type="submit"] { - display: inline-flex; - align-items: center; - justify-content: center; - min-height: 34px; - padding: 0 0.9rem; - border: 1px solid #7f8084; - border-radius: 4px; - background: #f7f7f7; - color: #1a1e23; - font-size: 14px; - font-weight: 700; - cursor: pointer; - font-family: inherit; -} -button:hover, .btn:hover, input[type="submit"]:hover { background: #ececef; text-decoration: none; } -button:active, .btn:active { transform: translateY(1px); } - -.banner { - border-radius: 4px; - padding: 0.65rem 0.8rem; - border: 1px solid #b4b5ba; - margin-bottom: 0.8rem; - background: #fafafa; -} -.banner.success { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); } -.banner.warning { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning-text); } -.banner.error, .error { background: var(--error-bg); border-color: var(--error-border); color: var(--error-text); } - -table { - width: 100%; - border-collapse: collapse; - background: var(--bg-secondary); - border: 1px solid var(--border); - border-radius: var(--radius); - overflow: hidden; -} -th, td { - padding: 0.7rem 0.8rem; - border-bottom: 1px solid var(--border); - text-align: left; - vertical-align: top; -} -th { background: #e7e7e8; font-size: 13px; text-transform: uppercase; letter-spacing: 0.04em; } -tr:last-child td { border-bottom: none; } -tr:hover td { background: rgba(0, 0, 0, 0.02); } - -code, pre { font-family: var(--font-mono); } -pre { - padding: 0.9rem; - background: #fff; - border: 1px solid var(--border); - border-radius: var(--radius); - overflow: auto; -} - -footer { - border-top: 1px solid var(--border); - background: #ffffff; - color: var(--text-muted); - padding: 1rem 1rem 1.5rem; - font-size: 13px; -} -.footer-inner { max-width: 1200px; margin: 0 auto; } - -input[type="range"] { - height: 6px; - padding: 0; - min-height: auto; - border: none; - background: #d4d5d9; - border-radius: 999px; - -webkit-appearance: none; - appearance: none; -} -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - width: 18px; - height: 18px; - background: var(--primary); - border-radius: 50%; - cursor: pointer; - box-shadow: 0 1px 3px rgba(0,0,0,0.2); -} -input[type="range"]::-moz-range-thumb { - width: 18px; - height: 18px; - background: var(--primary); - border-radius: 50%; - cursor: pointer; - border: none; - box-shadow: 0 1px 3px rgba(0,0,0,0.2); -} - -::selection { - background: rgba(15, 104, 173, 0.2); - color: var(--text-primary); -} - -@media (max-width: 860px) { - nav { - height: auto; - flex-direction: column; - } - .nav-menu { - flex-wrap: wrap; - } - .nav-menu > a:first-child { - min-width: 0; - } - .nav-account { - justify-content: flex-start; - padding: 0.6rem 0.7rem; - } - #content { - margin-top: 104px; - padding: 0.75rem; - } -} \ No newline at end of file diff --git a/site/info/uce-starter/themes/portal-light/icon.png b/site/info/uce-starter/themes/portal-light/icon.png deleted file mode 100644 index 8a42581..0000000 Binary files a/site/info/uce-starter/themes/portal-light/icon.png and /dev/null differ diff --git a/site/info/uce-starter/themes/portal-light/page.html.uce b/site/info/uce-starter/themes/portal-light/page.html.uce deleted file mode 100644 index d125df0..0000000 --- a/site/info/uce-starter/themes/portal-light/page.html.uce +++ /dev/null @@ -1,29 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - - DTree footer_props; - footer_props["embed_mode"].set_bool(embed_mode); - footer_props["inner_class"] = "footer-inner"; - - <> - - "> - - - - "> - - -
> - -
- - - - -} diff --git a/site/info/uce-starter/themes/retro-gaming/css/style.css b/site/info/uce-starter/themes/retro-gaming/css/style.css deleted file mode 100644 index f187fa6..0000000 --- a/site/info/uce-starter/themes/retro-gaming/css/style.css +++ /dev/null @@ -1,523 +0,0 @@ -/* ──────────────────────────────────────────────────────── - RETRO GAMING THEME - CRT scanlines · pixel font · neon glow · 8-bit palette - ──────────────────────────────────────────────────────── */ - -@font-face { - font-family: 'Press Start 2P'; - src: url('../../common/fonts/press-start-2p/press-start-2p-regular.ttf') format('truetype'); - font-style: normal; - font-weight: 400; - font-display: swap; -} - -/* ── tokens ─────────────────────────────────────────── */ -:root { - /* background */ - --bg-color: #0a0a1a; - --bg-secondary: #10102a; - --surface: #12122e; - --surface-elevated: #1a1a3e; - --surface-hover: #22224e; - - /* neon palette */ - --primary: #00ff88; - --primary-dark: #00cc6a; - --primary-light: #66ffbb; - --secondary: #ff00ff; - --accent: #ffff00; - --text-primary: #e0e0ff; - --text-secondary: #a0a0cc; - --text-muted: #6868a0; - - /* borders, shadows */ - --border: #2a2a5a; - --border-hover: #3a3a7a; - --shadow-sm: 0 2px 0 #000; - --shadow-md: 0 4px 0 #000, 0 0 12px rgba(0, 255, 136, 0.08); - --shadow-lg: 0 6px 0 #000, 0 0 24px rgba(0, 255, 136, 0.12); - --shadow-xl: 0 8px 0 #000, 0 0 40px rgba(0, 255, 136, 0.16); - - /* semantic */ - --success: #00ff88; - --success-bg: rgba(0, 255, 136, 0.1); - --success-border: rgba(0, 255, 136, 0.3); - --success-text: #00ff88; - --warning: #ffff00; - --warning-bg: rgba(255, 255, 0, 0.1); - --warning-border: rgba(255, 255, 0, 0.3); - --warning-text: #ffff00; - --error: #ff3366; - --error-bg: rgba(255, 51, 102, 0.1); - --error-border: rgba(255, 51, 102, 0.3); - --error-text: #ff3366; - --info: #00ccff; - --info-bg: rgba(0, 204, 255, 0.1); - --info-border: rgba(0, 204, 255, 0.3); - --info-text: #00ccff; - - /* geometry */ - --radius: 0px; - --radius-sm: 0px; - --radius-md: 0px; - --radius-lg: 2px; - --radius-xl: 4px; - - /* typography */ - --font-sans: 'Press Start 2P', monospace; - --font-mono: 'Press Start 2P', monospace; -} - -/* ── reset ──────────────────────────────────────────── */ -* { margin: 0; padding: 0; box-sizing: border-box; } -html { font-size: 16px; scroll-behavior: smooth; image-rendering: pixelated; } - -body { - font-family: var(--font-sans); - font-size: 10px; - line-height: 2; - color: var(--text-primary); - background: var(--bg-color); - -webkit-font-smoothing: none; - -moz-osx-font-smoothing: unset; -} - -/* ── CRT scanline overlay ───────────────────────────── */ -body::before { - content: ''; - position: fixed; - inset: 0; - background: repeating-linear-gradient( - 0deg, - transparent, - transparent 2px, - rgba(0, 0, 0, 0.15) 2px, - rgba(0, 0, 0, 0.15) 4px - ); - pointer-events: none; - z-index: 9000; -} - -/* subtle vignette */ -body::after { - content: ''; - position: fixed; - inset: 0; - background: radial-gradient(ellipse at center, transparent 60%, rgba(0, 0, 0, 0.5) 100%); - pointer-events: none; - z-index: 8999; -} - -::selection { - background: var(--primary); - color: var(--bg-color); -} - -/* ── links ──────────────────────────────────────────── */ -a { - color: var(--primary); - text-decoration: none; - transition: color 0.1s step-end; -} -a:hover { - color: var(--accent); - text-decoration: none; - text-shadow: 0 0 6px var(--accent); -} - -/* ── navigation ─────────────────────────────────────── */ -nav { - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 1000; - background: var(--bg-secondary); - border-bottom: 3px solid var(--primary); - padding: 0 0.5rem; - display: flex; - align-items: center; - box-shadow: 0 3px 0 #000, 0 6px 20px rgba(0, 255, 136, 0.15); -} - -.nav-menu { - display: flex; - align-items: center; - gap: 0; - flex: 1; - min-width: 0; - overflow-x: auto; - scrollbar-width: none; -} -.nav-menu::-webkit-scrollbar { display: none; } - -.nav-menu a, -.nav-account a { - display: inline-flex; - align-items: center; - padding: 0.75rem 0.8rem; - color: var(--text-secondary); - text-decoration: none; - font-size: 8px; - letter-spacing: 0.5px; - text-transform: uppercase; - border-right: 1px solid var(--border); - transition: background 0.1s step-end, color 0.1s step-end; -} - -.nav-menu > a:first-child { - color: var(--primary); - text-shadow: 0 0 8px rgba(0, 255, 136, 0.5); - font-size: 10px; - padding: 0.75rem 1rem; - border-right: 2px solid var(--primary); -} - -.nav-menu a:hover, -.nav-account a:hover { - background: var(--surface-hover); - color: var(--accent); - text-shadow: 0 0 6px var(--accent); - text-decoration: none; -} - -.nav-account { - margin-left: auto; - display: flex; - align-items: center; - gap: 0; - flex: 0 0 auto; - overflow: visible; -} -.nav-account a { - border-right: none; - border-left: 1px solid var(--border); -} - -.nav-account .account-name { - color: var(--primary); - font-size: 8px; - padding: 0 0.5rem; -} - -.nav-account .nav-avatar, -.profile-avatar { - border-radius: 0; - border: 2px solid var(--primary); - image-rendering: pixelated; -} -.nav-account .nav-avatar { width: 24px; height: 24px; } -.profile-avatar { width: 64px; height: 64px; } - -/* ── main content ───────────────────────────────────── */ -#content { - margin-top: 3.5rem; - min-height: calc(100vh - 7rem); - padding: 1.5rem 1rem; - max-width: 1100px; - margin-left: auto; - margin-right: auto; - position: relative; - z-index: 1; -} - -/* ── typography ─────────────────────────────────────── */ -h1, h2, h3, h4, h5, h6 { - font-weight: 400; - line-height: 2; - margin-bottom: 0.75rem; - color: var(--primary); - text-shadow: 0 0 10px rgba(0, 255, 136, 0.35); - text-transform: uppercase; -} - -h1 { - font-size: 16px; - padding: 0.75rem 0; - border-bottom: 3px double var(--primary); - margin-bottom: 1.25rem; - position: relative; -} -h1::before { - content: '►'; - margin-right: 0.5rem; - animation: blink-cursor 1s step-end infinite; -} -h2 { font-size: 12px; color: var(--info-text); text-shadow: 0 0 8px rgba(0, 204, 255, 0.3); } -h3 { font-size: 10px; color: var(--secondary); text-shadow: 0 0 8px rgba(255, 0, 255, 0.3); } -h4, h5, h6 { font-size: 10px; } - -p { margin: 0 0 0.75rem; } - -@keyframes blink-cursor { - 0%, 100% { opacity: 1; } - 50% { opacity: 0; } -} - -/* ── cards / blocks ─────────────────────────────────── */ -#content > div:not(.ws-app):not(.demo-section), -.block, -.card, -.dashboard-panel { - background: var(--surface); - border: 2px solid var(--border); - padding: 1rem; - margin-bottom: 1.25rem; - box-shadow: var(--shadow-md); - position: relative; - transition: border-color 0.1s step-end; -} - -#content > div:not(.ws-app):not(.demo-section)::before, -.block::before, -.card::before, -.dashboard-panel::before { - content: ''; - position: absolute; - top: 0; left: 0; right: 0; - height: 2px; - background: linear-gradient(90deg, var(--primary), var(--secondary), var(--accent)); -} - -#content > div:not(.ws-app):not(.demo-section):hover, -.block:hover, -.card:hover, -.dashboard-panel:hover { - border-color: var(--border-hover); - box-shadow: var(--shadow-lg); -} - -/* ── forms ──────────────────────────────────────────── */ -form { max-width: 640px; } -form > div { display: grid; gap: 0.35rem; margin-bottom: 1rem; } - -label { - color: var(--accent); - font-size: 8px; - text-transform: uppercase; - letter-spacing: 1px; -} - -input, select, textarea { - width: 100%; - padding: 0.6rem 0.7rem; - border: 2px solid var(--border); - background: var(--bg-color); - color: var(--primary); - font-family: var(--font-mono); - font-size: 10px; - caret-color: var(--primary); -} -textarea { min-height: 100px; } - -input:focus, select:focus, textarea:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 1px var(--primary), 0 0 12px rgba(0, 255, 136, 0.2); -} - -input::placeholder, textarea::placeholder { - color: var(--text-muted); - opacity: 1; -} - -/* ── buttons ────────────────────────────────────────── */ -button, .btn, input[type="submit"] { - display: inline-flex; - align-items: center; - justify-content: center; - padding: 0.6rem 1.2rem; - border: 2px solid var(--primary); - background: transparent; - color: var(--primary); - font-family: var(--font-sans); - font-size: 9px; - text-transform: uppercase; - letter-spacing: 0.5px; - cursor: pointer; - transition: all 0.1s step-end; - box-shadow: 3px 3px 0 var(--bg-color), 4px 4px 0 var(--primary); -} - -button:hover, .btn:hover, input[type="submit"]:hover { - background: var(--primary); - color: var(--bg-color); - text-shadow: none; - box-shadow: 1px 1px 0 var(--bg-color), 2px 2px 0 var(--primary); - transform: translate(2px, 2px); - text-decoration: none; -} - -button:active, .btn:active, input[type="submit"]:active { - box-shadow: none; - transform: translate(4px, 4px); -} - -.btn-secondary { - border-color: var(--secondary); - color: var(--secondary); - box-shadow: 3px 3px 0 var(--bg-color), 4px 4px 0 var(--secondary); -} -.btn-secondary:hover { - background: var(--secondary); - color: var(--bg-color); - box-shadow: 1px 1px 0 var(--bg-color), 2px 2px 0 var(--secondary); -} - -.btn-outline { - border-color: var(--accent); - color: var(--accent); - box-shadow: 3px 3px 0 var(--bg-color), 4px 4px 0 var(--accent); -} -.btn-outline:hover { - background: var(--accent); - color: var(--bg-color); - box-shadow: 1px 1px 0 var(--bg-color), 2px 2px 0 var(--accent); -} - -/* ── range slider ───────────────────────────────────── */ -input[type="range"] { - height: 8px; - padding: 0; - border: 2px solid var(--border); - background: var(--bg-color); - -webkit-appearance: none; - appearance: none; -} -input[type="range"]::-webkit-slider-thumb { - -webkit-appearance: none; - width: 14px; - height: 14px; - background: var(--primary); - border: 2px solid var(--bg-color); - cursor: pointer; - box-shadow: 0 0 6px rgba(0, 255, 136, 0.4); -} -input[type="range"]::-moz-range-thumb { - width: 14px; - height: 14px; - background: var(--primary); - border: 2px solid var(--bg-color); - border-radius: 0; - cursor: pointer; - box-shadow: 0 0 6px rgba(0, 255, 136, 0.4); -} - -/* ── banners ────────────────────────────────────────── */ -.banner { - padding: 0.6rem 0.8rem; - border: 2px solid var(--border); - margin-bottom: 0.75rem; - background: var(--surface); -} -.banner.success { background: var(--success-bg); border-color: var(--success-border); color: var(--success-text); } -.banner.warning { background: var(--warning-bg); border-color: var(--warning-border); color: var(--warning-text); } -.banner.error, .error { background: var(--error-bg); border-color: var(--error-border); color: var(--error-text); } - -/* ── tables ─────────────────────────────────────────── */ -table { - width: 100%; - border-collapse: collapse; - background: var(--surface); - border: 2px solid var(--border); -} -th, td { - padding: 0.5rem 0.65rem; - border-bottom: 1px solid var(--border); - text-align: left; - font-size: 9px; -} -th { - background: var(--surface-elevated); - color: var(--accent); - text-transform: uppercase; - letter-spacing: 0.5px; - border-bottom: 2px solid var(--accent); -} -tr:last-child td { border-bottom: none; } -tr:hover td { background: rgba(0, 255, 136, 0.04); } - -/* ── code ───────────────────────────────────────────── */ -code, pre { font-family: var(--font-mono); } -pre { - padding: 0.75rem; - background: var(--bg-color); - border: 2px solid var(--border); - overflow: auto; - color: var(--primary); -} - -/* ── footer ─────────────────────────────────────────── */ -footer { - border-top: 3px solid var(--primary); - padding: 1rem; - color: var(--text-muted); - font-size: 8px; - background: var(--bg-secondary); - box-shadow: 0 -3px 0 #000; - position: relative; - z-index: 1; -} -footer::before { - content: '// '; - color: var(--text-muted); -} - -/* ── pixel decoration classes (for page template) ──── */ -.retro-stars { - position: fixed; - inset: 0; - z-index: 0; - pointer-events: none; - background: - radial-gradient(1px 1px at 10% 15%, var(--primary), transparent), - radial-gradient(1px 1px at 30% 45%, var(--accent), transparent), - radial-gradient(1px 1px at 55% 20%, var(--secondary), transparent), - radial-gradient(1px 1px at 70% 65%, var(--info-text), transparent), - radial-gradient(1px 1px at 85% 30%, var(--primary), transparent), - radial-gradient(1px 1px at 15% 75%, var(--accent), transparent), - radial-gradient(1px 1px at 45% 85%, var(--secondary), transparent), - radial-gradient(1px 1px at 90% 80%, var(--primary), transparent), - radial-gradient(1px 1px at 25% 55%, var(--info-text), transparent), - radial-gradient(1px 1px at 60% 50%, var(--accent), transparent), - radial-gradient(1px 1px at 5% 40%, var(--error-text), transparent), - radial-gradient(1px 1px at 75% 10%, var(--accent), transparent), - radial-gradient(1px 1px at 40% 30%, var(--primary), transparent), - radial-gradient(1px 1px at 95% 55%, var(--secondary), transparent), - radial-gradient(1px 1px at 50% 70%, var(--primary), transparent), - radial-gradient(1px 1px at 20% 90%, var(--info-text), transparent); - animation: twinkle 4s ease-in-out infinite alternate; -} -@keyframes twinkle { - 0% { opacity: 0.4; } - 100% { opacity: 0.8; } -} - -/* ── responsive ─────────────────────────────────────── */ -@media (max-width: 860px) { - nav { flex-wrap: wrap; } - .nav-menu { overflow-x: auto; white-space: nowrap; } - .nav-account { - width: 100%; - margin-left: 0; - border-top: 1px solid var(--border); - justify-content: flex-start; - } - #content { margin-top: 5rem; padding: 1rem 0.75rem; } - h1 { font-size: 12px; } - h2 { font-size: 10px; } -} - -/* ── focus accessibility ────────────────────────────── */ -button:focus, .btn:focus, input:focus, textarea:focus, select:focus { - outline: 2px solid var(--primary); - outline-offset: 2px; -} - -/* ── print ──────────────────────────────────────────── */ -@media print { - nav, footer, .retro-stars { display: none; } - body::before, body::after { display: none; } - #content { margin-top: 0; } - * { background: white !important; color: black !important; box-shadow: none !important; text-shadow: none !important; } -} diff --git a/site/info/uce-starter/themes/retro-gaming/icon.png b/site/info/uce-starter/themes/retro-gaming/icon.png deleted file mode 100644 index 12dfe2c..0000000 Binary files a/site/info/uce-starter/themes/retro-gaming/icon.png and /dev/null differ diff --git a/site/info/uce-starter/themes/retro-gaming/page.html.uce b/site/info/uce-starter/themes/retro-gaming/page.html.uce deleted file mode 100644 index c0a53da..0000000 --- a/site/info/uce-starter/themes/retro-gaming/page.html.uce +++ /dev/null @@ -1,32 +0,0 @@ -#load "../../lib/app.uce" - -COMPONENT(Request& context) -{ - starter_boot(context); - bool embed_mode = starter_page_embed_mode(context); - String main_html = starter_page_main_html(context); - - DTree nav_props; - nav_props["account_wrapper_class"] = "nav-account nav-menu"; - - DTree footer_props; - footer_props["embed_mode"].set_bool(embed_mode); - - <> - - "> - - - - > -
- - -
> - -
- - - - -} diff --git a/site/info/uce-starter/views/account/login.uce b/site/info/uce-starter/views/account/login.uce deleted file mode 100644 index 89d5682..0000000 --- a/site/info/uce-starter/views/account/login.uce +++ /dev/null @@ -1,28 +0,0 @@ -#load "../../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Login"; - StarterUser users(context); - DTree result; - if(context.params["REQUEST_METHOD"] == "POST") - { - result = users.sign_in(context.post["email"], context.post["password"]); - if(result["result"].to_string() != "") - { - starter_redirect("account/profile", context); - return; - } - } - <> -

Login

- -
-
-
- -
-

">Register

- -} diff --git a/site/info/uce-starter/views/account/logout.uce b/site/info/uce-starter/views/account/logout.uce deleted file mode 100644 index cfee83b..0000000 --- a/site/info/uce-starter/views/account/logout.uce +++ /dev/null @@ -1,8 +0,0 @@ -#load "../../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - StarterUser(context).logout(); - starter_redirect("account/login", context); -} diff --git a/site/info/uce-starter/views/account/profile.uce b/site/info/uce-starter/views/account/profile.uce deleted file mode 100644 index 17fbc14..0000000 --- a/site/info/uce-starter/views/account/profile.uce +++ /dev/null @@ -1,27 +0,0 @@ -#load "../../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - StarterUser users(context); - if(!users.is_signed_in()) - { - starter_redirect("account/login", context); - return; - } - context.var["starter"]["page_title"] = "Profile"; - DTree user = users.current(); - String roles = ""; - user["roles"].each([&](DTree role, String key) { - if(roles != "") - roles += ", "; - roles += role.to_string(); - }); - <> -

Profile

-

Email:

-

Roles:

-

Created:

-

">Logout

- -} diff --git a/site/info/uce-starter/views/account/register.uce b/site/info/uce-starter/views/account/register.uce deleted file mode 100644 index 8f92f47..0000000 --- a/site/info/uce-starter/views/account/register.uce +++ /dev/null @@ -1,22 +0,0 @@ -#load "../../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Register"; - StarterUser users(context); - DTree result; - if(context.params["REQUEST_METHOD"] == "POST") - result = users.create(context.post["email"], context.post["password"]); - - <> -

Register

- - -
-
-
- -
- -} diff --git a/site/info/uce-starter/views/auth/callback.uce b/site/info/uce-starter/views/auth/callback.uce deleted file mode 100644 index 5775764..0000000 --- a/site/info/uce-starter/views/auth/callback.uce +++ /dev/null @@ -1,50 +0,0 @@ -#load "../../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "OAuth Callback"; - String code = context.get["code"]; - String state = context.get["state"]; - String error = context.get["error"]; - String error_description = context.get["error_description"]; - - <> -
-
- - - -
-
-

Authentication Successful

-

OAuth callback received successfully! Demo mode is active until real provider credentials are configured.

-
-

Service:

-

Code: ...

-

State:

-
- -
- -
-
-

Invalid Callback

-

Missing required OAuth parameters.

-
- -
-
- -} diff --git a/site/info/uce-starter/views/auth/demo.uce b/site/info/uce-starter/views/auth/demo.uce deleted file mode 100644 index c259605..0000000 --- a/site/info/uce-starter/views/auth/demo.uce +++ /dev/null @@ -1,40 +0,0 @@ -#load "../../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Auth"; - starter_register_css("views/marketing.css", context); - - DTree 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"; - props["github_client_id"] = "YOUR_GITHUB_CLIENT_ID"; - props["discord_client_id"] = "YOUR_DISCORD_CLIENT_ID"; - props["twitch_client_id"] = "YOUR_TWITCH_CLIENT_ID"; - props["callback_url"] = starter_link("auth/callback", context); - - <> -

Authentication Demo

-
-

OAuth Authentication

-

This component provides secure OAuth authentication with popular identity providers.

- -
-
-

Current Session Status

- -
-

Logged In

-

User ID:

-
- -
-

Not Logged In

-

Use the OAuth component above to sign in with Google, GitHub, Discord, or Twitch.

-
- -
- -} diff --git a/site/info/uce-starter/views/auth/store-oauth-session.uce b/site/info/uce-starter/views/auth/store-oauth-session.uce deleted file mode 100644 index 01868e4..0000000 --- a/site/info/uce-starter/views/auth/store-oauth-session.uce +++ /dev/null @@ -1,21 +0,0 @@ -#load "../../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_type"] = "json"; - - DTree 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(); - context.session["oauth_state"] = body["oauth_state"].to_string(); - context.var["starter"]["json"]["status"] = "success"; - } - else - { - context.set_status(400, "Bad Request"); - context.var["starter"]["json"]["status"] = "error"; - context.var["starter"]["json"]["message"] = "Invalid input"; - } -} diff --git a/site/info/uce-starter/views/dashboard.css b/site/info/uce-starter/views/dashboard.css deleted file mode 100644 index ce90e84..0000000 --- a/site/info/uce-starter/views/dashboard.css +++ /dev/null @@ -1,205 +0,0 @@ -.dashboard-intro p, -.dashboard-panel-header p, -.dashboard-note { - color: var(--text-secondary); - max-width: 72ch; -} - -.dashboard-panel { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg); - box-shadow: var(--shadow-md); - margin-bottom: 2rem; - overflow: hidden; - padding: 1.5rem; -} - -.dashboard-panel-header { - display: flex; - flex-direction: column; - gap: 0.35rem; - margin-bottom: 1.25rem; -} - -.dashboard-panel-header h2 { - font-size: 1.4rem; - margin-bottom: 0; -} - -.dashboard-stat-grid { - display: grid; - gap: 1rem; - grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); -} - -.dashboard-stat-card { - background: var(--bg-secondary); - border: 1px solid var(--border); - border-radius: var(--radius); - box-shadow: var(--shadow-sm); - color: inherit; - display: flex; - flex-direction: column; - gap: 0.4rem; - padding: 1rem; - text-decoration: none; - transition: transform 0.16s ease, box-shadow 0.16s ease, border-color 0.16s ease; - position: relative; - overflow: hidden; -} - -.dashboard-stat-card:hover { - transform: translateY(-2px); - box-shadow: var(--shadow-md); - text-decoration: none; -} - -.dashboard-stat-card::before { - content: ''; - position: absolute; - inset: 0 auto 0 0; - width: 4px; - background: var(--primary); -} - -.dashboard-stat-card.tone-success::before { - background: var(--success); -} - -.dashboard-stat-card.tone-warning::before { - background: var(--warning); -} - -.dashboard-stat-card.tone-danger::before { - background: var(--error); -} - -.dashboard-stat-card.tone-info::before { - background: var(--info); -} - -.dashboard-stat-label { - color: var(--text-secondary); - font-size: 0.85rem; - font-weight: 600; - letter-spacing: 0.04em; - text-transform: uppercase; -} - -.dashboard-stat-value { - font-size: clamp(1.6rem, 2vw, 2.1rem); - font-variant-numeric: tabular-nums; - font-weight: 700; - line-height: 1.1; -} - -.dashboard-stat-meta { - color: var(--text-secondary); - font-size: 0.92rem; -} - -.dashboard-chart-canvas { - background: - radial-gradient(circle at top left, rgba(255, 255, 255, 0.05), transparent 45%), - linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(15, 23, 42, 0.08)); - border: 1px solid var(--border); - border-radius: var(--radius); - display: block; - width: 100%; - min-height: 180px; -} - -.dashboard-table-wrap { - overflow-x: auto; - border: 1px solid var(--border); - border-radius: var(--radius); -} - -.u-sortable-table { - border-collapse: collapse; - font-size: 0.95rem; - min-width: 720px; - width: 100%; -} - -.u-sortable-table thead th { - background: var(--surface-elevated); - border-bottom: 1px solid var(--border); - color: var(--text-primary); - font-size: 0.78rem; - font-weight: 700; - letter-spacing: 0.05em; - padding: 0.85rem 1rem; - position: relative; - text-transform: uppercase; - white-space: nowrap; -} - -.u-sortable-table thead th.sortable { - cursor: pointer; - padding-right: 2rem; - user-select: none; -} - -.u-sortable-table thead th.sortable::after { - content: ':'; - color: var(--text-muted); - position: absolute; - right: 0.75rem; - top: 50%; - transform: translateY(-50%); - font-size: 0.8rem; -} - -.u-sortable-table thead th.sorted-asc::after { - content: '^'; - color: var(--primary); -} - -.u-sortable-table thead th.sorted-desc::after { - content: 'v'; - color: var(--primary); -} - -.u-sortable-table tbody tr:nth-child(odd) { - background: rgba(148, 163, 184, 0.05); -} - -.u-sortable-table tbody tr:hover { - background: rgba(96, 165, 250, 0.08); -} - -.u-sortable-table td { - border-bottom: 1px solid var(--border); - padding: 0.85rem 1rem; - vertical-align: top; - font-variant-numeric: tabular-nums; -} - -.u-sortable-table tbody tr:last-child td { - border-bottom: none; -} - -.u-sortable-table .align-right { - text-align: right; -} - -.u-sortable-table .align-center { - text-align: center; -} - -.u-sortable-table .muted { - color: var(--text-secondary); - text-align: center; -} - -@media (max-width: 768px) { - .dashboard-panel { - padding: 1rem; - } - - .u-sortable-table { - min-width: 600px; - } -} \ No newline at end of file diff --git a/site/info/uce-starter/views/dashboard.uce b/site/info/uce-starter/views/dashboard.uce deleted file mode 100644 index 14c71b6..0000000 --- a/site/info/uce-starter/views/dashboard.uce +++ /dev/null @@ -1,70 +0,0 @@ -#load "../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Dashboard"; - starter_register_css("views/dashboard.css", context); - - DTree props; - DTree 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(); - item["label"] = "Healthy Services"; item["value"] = "3 / 4"; item["meta"] = "one degraded background worker"; item["tone"] = "danger"; props["items"].push(item); - props["title"] = "Starter-Friendly Overview Cards"; - props["subtitle"] = "Small summary tiles work well across admin pages, internal tools, and SSR dashboards."; - - <> -

Dashboard Primitives

-

This page is the first backport slice from the LocalAI dashboard frontend. It keeps the generic parts that fit the starter itself.

- - print(component("../components/data/widgets:SUMMARY_METRICS", props, context)); - - props.clear(); - DTree series; - DTree values; - DTree 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(); - entry["key"] = "latency"; entry["label"] = "Latency"; entry["color"] = "#f59e0b"; entry["axis"] = "right"; entry["format"] = "duration-ms"; - values = "182"; entry["values"].push(values); values = "176"; entry["values"].push(values); values = "191"; entry["values"].push(values); values = "204"; entry["values"].push(values); values = "188"; entry["values"].push(values); values = "166"; entry["values"].push(values); values = "159"; entry["values"].push(values); - props["series"].push(entry); - values = "08:00"; props["x_labels"].push(values); values = "09:00"; props["x_labels"].push(values); values = "10:00"; props["x_labels"].push(values); values = "11:00"; props["x_labels"].push(values); values = "12:00"; props["x_labels"].push(values); values = "13:00"; props["x_labels"].push(values); values = "14:00"; props["x_labels"].push(values); - props["id"] = "dashboard-demo-traffic"; - props["title"] = "Requests vs Latency"; - props["subtitle"] = "Same generic chart primitive can track throughput, job backlog, token volume, or queue time."; - props["height"] = "320"; - props["x_axis_label"] = "Last 7 Hours"; - props["y_axis_left_label"] = "Requests"; - props["y_axis_right_label"] = "Latency"; - props["y_axis_left_format"] = "count"; - props["y_axis_right_format"] = "duration-ms"; - print(component("../components/data/widgets:TIMESERIES_CHART", props, context)); - - props.clear(); - props["id"] = "dashboard-service-table"; - props["title"] = "Service Snapshot"; - props["subtitle"] = "Vanilla HTML table enhancement for cases where ag-Grid is overkill."; - props["storage_key"] = "starter.dashboard.services"; - props["sort"]["column"] = "2"; - props["sort"]["direction"] = "desc"; - DTree 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; - 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(); - row["service"] = "sandbox"; row["uptime"] = "19 hours"; row["requests"] = "12810"; row["memory"] = "295698432"; row["p95_latency"] = "418"; row["healthy"] = "false"; props["rows"].push(row); - print(component("../components/data/widgets:SORTABLE_TABLE", props, context)); - - <> -

What Was Backported

The charting logic and data-formatting ideas come directly from the more complex dashboard frontend, but the starter version is stripped down to generic building blocks.

- -} diff --git a/site/info/uce-starter/views/features.uce b/site/info/uce-starter/views/features.uce deleted file mode 100644 index 3455fee..0000000 --- a/site/info/uce-starter/views/features.uce +++ /dev/null @@ -1,13 +0,0 @@ -#load "../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Features"; - starter_register_css("views/marketing.css", context); - <> -

Features

-

This page exists in the UCE port so the starter menu resolves cleanly as a full route, while still reusing the same marketing components as the home page.

- - print(component("../components/example/marketing_blocks:FEATURES_GRID", context)); -} diff --git a/site/info/uce-starter/views/gauges.uce b/site/info/uce-starter/views/gauges.uce deleted file mode 100644 index 1c6bf73..0000000 --- a/site/info/uce-starter/views/gauges.uce +++ /dev/null @@ -1,130 +0,0 @@ -#load "../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Gauges"; - starter_register_css("themes/common/css/gauges.css", context); - f64 pi = 3.14159265358979323846; - - DTree props; - DTree item; - - <> -

Gauge Components Demo

-
- - - props["id"] = "horizontal_demo"; - props["title"] = "Horizontal Progress Bar"; - props["subtitle"] = "The original bar gauges, restyled to share the same card and token language as the new arc gauges."; - props["layout"] = "horizontal"; - props["style"] = "flex:1 1 24rem"; - props["listen"].set_bool(true); - props["markers"]["zero"]["value"] = "0"; - props["markers"]["zero"]["label"] = "Zero"; - props["markers"]["zero"]["color"] = "var(--bg-color)"; - props["markers"]["high"]["value"] = "100"; - props["markers"]["high"]["label"] = "High"; - item["value"] = "45"; item["min"] = "0"; item["max"] = "200"; item["label"] = "CPU"; item["tooltip"] = "CPU Usage"; - item["color"]["0"]["from"] = "-50"; item["color"]["0"]["to"] = "20"; item["color"]["0"]["color"] = "var(--text-muted)"; - item["color"]["1"]["from"] = "20"; item["color"]["1"]["to"] = "80"; item["color"]["1"]["color"] = "var(--primary)"; - item["color"]["2"]["from"] = "80"; item["color"]["2"]["to"] = "100"; item["color"]["2"]["color"] = "var(--warning)"; - props["items"]["cpu"] = item; item.clear(); - item["value"] = "92"; item["min"] = "-50"; item["max"] = "100"; item["label"] = "Memory"; item["tooltip"] = "Memory Usage"; props["items"]["memory"] = item; item.clear(); - item["value"] = "28"; item["min"] = "0"; item["max"] = "100"; item["label"] = "Disk I/O"; item["tooltip"] = "Disk I/O"; props["items"]["disk"] = item; - print(component("../components/gauges/progressbar", props, context)); - - props.clear(); - props["id"] = "vertical_demo"; - props["title"] = "Vertical Progress Bar"; - props["subtitle"] = "Same abstraction, but stacked as compact KPI cards."; - props["layout"] = "vertical"; - props["style"] = "flex:1 1 24rem"; - props["height"] = "350"; - props["listen"].set_bool(true); - props["markers"]["zero"]["value"] = "0"; - props["markers"]["zero"]["label"] = "Zero"; - props["markers"]["zero"]["color"] = "var(--bg-color)"; - props["markers"]["high"]["value"] = "100"; - props["markers"]["high"]["label"] = "High"; - item.clear(); item["value"] = "45"; item["min"] = "0"; item["max"] = "200"; item["label"] = "CPU"; item["tooltip"] = "CPU Usage"; props["items"]["cpu"] = item; - item.clear(); item["value"] = "92"; item["min"] = "-50"; item["max"] = "100"; item["label"] = "RAM"; item["tooltip"] = "Memory Usage"; props["items"]["memory"] = item; - item.clear(); item["value"] = "28"; item["min"] = "0"; item["max"] = "100"; item["label"] = "I/O"; item["tooltip"] = "Disk I/O"; props["items"]["disk"] = item; - print(component("../components/gauges/progressbar", props, context)); - - <> -
-
-

Event Binding

-
-
-
-
-
-
-
- - - props.clear(); - props["id"] = "needle_demo"; - props["title"] = "Needle Gauge"; - props["subtitle"] = "The original analog gauge now uses the same elevated panels, typography, and theme-token palette as the arc gauges."; - props["style"] = "flex:1 1 24rem"; - props["listen"].set_bool(true); - props["label"] = "CPU"; - props["tooltip"] = "CPU Usage"; - props["scale"]["angle_start"] = std::to_string(-1.2 * pi); - props["scale"]["angle_end"] = std::to_string(0.2 * pi); - props["scale"]["max"] = "100"; - props["scale"]["unit"] = "%"; - props["scale"]["ticks-every"] = "10"; - props["scale"]["value-labels-every"] = "20"; - props["scale"]["tick-color"] = "var(--text-muted)"; - props["scale"]["color"]["0"]["from"] = "-50"; - props["scale"]["color"]["0"]["to"] = "10"; - props["scale"]["color"]["0"]["color"] = "var(--primary)"; - props["scale"]["color"]["1"]["from"] = "10"; - props["scale"]["color"]["1"]["to"] = "70"; - props["scale"]["color"]["1"]["color"] = "var(--text-muted)"; - props["scale"]["color"]["2"]["from"] = "70"; - props["scale"]["color"]["2"]["to"] = "90"; - props["scale"]["color"]["2"]["color"] = "var(--warning)"; - props["scale"]["color"]["3"]["from"] = "90"; - props["scale"]["color"]["3"]["to"] = "200"; - props["scale"]["color"]["3"]["color"] = "var(--error)"; - item.clear(); item["max"] = "200"; item["value"] = "45"; item["label"] = "CPU"; props["items"]["cpu"] = item; - item.clear(); item["value"] = "92"; item["min"] = "-50"; item["label"] = "Memory"; item["tooltip"] = "Memory Usage"; props["items"]["memory"] = item; - item.clear(); item["value"] = "28"; item["label"] = "Disk I/O"; item["tooltip"] = "Disk I/O"; props["items"]["disk"] = item; - print(component("../components/gauges/needlegauge", props, context)); - - <> -
-
- - - props.clear(); - props["id"] = "arc_demo"; - props["title"] = "SVG Arc Gauges"; - props["subtitle"] = "Backported from the llm2 overview as reusable KPI-style gauges with optional watermark tracking."; - props["style"] = "flex: 2 1 36rem"; - props["listen"].set_bool(true); - item.clear(); item["label"] = "System Load"; item["value"] = "1.8"; item["max"] = "8"; item["precision"] = "1"; item["caption"] = "LOAD 1M"; item["meta"] = "4 cores available"; item["watermark_prefix"] = "loadDemo"; - item["color"]["0"]["from"] = "0"; item["color"]["0"]["to"] = "3.5"; item["color"]["0"]["color"] = "var(--success, #10b981)"; - item["color"]["1"]["from"] = "3.5"; item["color"]["1"]["to"] = "6"; item["color"]["1"]["color"] = "var(--warning, #f59e0b)"; - item["color"]["2"]["from"] = "6"; item["color"]["2"]["to"] = "8"; item["color"]["2"]["color"] = "var(--error, #ef4444)"; - props["items"]["load"] = item; - item.clear(); item["label"] = "Memory"; item["value"] = "62"; item["max"] = "100"; item["precision"] = "0"; item["unit"] = "%"; item["caption"] = "MEMORY"; item["meta"] = "9.9 / 16 GB"; item["watermark_prefix"] = "memoryDemo"; props["items"]["memory_arc"] = item; - item.clear(); item["label"] = "Network"; item["value"] = "18"; item["max"] = "100"; item["precision"] = "0"; item["unit"] = " MB/s"; item["caption"] = "THROUGHPUT"; item["meta"] = "Inbound + outbound"; item["watermark_prefix"] = "networkDemo"; props["items"]["network"] = item; - print(component("../components/gauges/arcgauge", props, context)); - - <> -
-

Arc Gauge Controls

-
-
-
-
-
- -} diff --git a/site/info/uce-starter/views/index.uce b/site/info/uce-starter/views/index.uce deleted file mode 100644 index 9b3fa50..0000000 --- a/site/info/uce-starter/views/index.uce +++ /dev/null @@ -1,128 +0,0 @@ -#load "../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Home"; - starter_register_css("views/marketing.css", context); - - DTree 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."; - props["cta_text"] = "Get Started Free(mium)"; - props["cta_link"] = "#features"; - print(component("../components/example/marketing_blocks:HERO_SECTION", props, context)); - print(component("../components/example/marketing_blocks:FEATURES_GRID", context)); - - props.clear(); - DTree 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(); - stat["number"] = "24/7"; stat["label"] = "Support"; props["stats"].push(stat); - print(component("../components/example/marketing_blocks:STATS_SECTION", props, context)); - print(component("../components/example/marketing_blocks:BRANDS_SHOWCASE", context)); - print(component("../components/example/marketing_blocks:TESTIMONIALS", context)); - print(component("../components/example/marketing_blocks:PRICING_TABLE", context)); - - <> -
-
-

Demo

-

Try our unbelievable components in action

-
-
-

Modern Forms

-
-
- - -
-
- - -
-
- - -
- -
-
-
-

Button Variations

-
- - - - -
-
- - - -
-
-
-
-
-
-

Theme Families

-

Compare the starter’s built-in theme families and jump to the live gallery.

-
-
-

-

- ">Preview Theme -
-
-

Starter Themes

-

The original light and dark starter skins remain available in the same gallery for side-by-side checks.

- ">Open Gallery -
-
-
- - - props.clear(); - props["title"] = "Ready to Transform Your Development?"; - props["subtitle"] = "Join thousands of developers who have already modernized their workflow with our framework."; - props["cta_text"] = "Start Your Project"; - props["secondary_text"] = "View GitHub"; - print(component("../components/example/marketing_blocks:CTA_SECTION", props, context)); - - <> -
-

Component Development Guidelines

-
-
🏷️Use semantic HTML5 elements
-
🎨Implement CSS custom properties for theming
-
📱Add responsive design with mobile-first approach
-
Include accessibility attributes
-
Use progressive enhancement for JavaScript features
-
-
- - - props.clear(); - DTree 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(); - row["name"] = "Alice Brown"; row["age"] = "40"; row["gender"] = "female"; row["department"] = "Engineering"; row["salary"] = "95000"; row["active"] = "true"; props["items"].push(row); - props["height"] = "350px"; - <> -
-

Simple Data Table (ag-Grid)

-

Basic data table with auto-generated columns, sorting, and filtering:

- -
- -} diff --git a/site/info/uce-starter/views/marketing.css b/site/info/uce-starter/views/marketing.css deleted file mode 100755 index 77c5028..0000000 --- a/site/info/uce-starter/views/marketing.css +++ /dev/null @@ -1,233 +0,0 @@ - -/* Shared base styles */ -.mono-text, -.code-block { - font-family: 'SF Mono', 'Monaco', 'Menlo', monospace; -} - -/* Code block container with terminal styling */ -.code-block-container { - background: linear-gradient(135deg, var(--surface) 0%, var(--surface-elevated) 100%); - padding: 2rem; - border-radius: var(--radius-lg); - border: 1px solid var(--border); - margin: 1rem 0; - position: relative; - overflow: hidden; -} - -/* Terminal header bar */ -.terminal-header { - position: absolute; - top: 0; - left: 0; - right: 0; - height: 3px; -} - -.terminal-header.primary-gradient { - background: linear-gradient(90deg, var(--primary) 0%, var(--secondary) 50%, var(--accent) 100%); -} - -.terminal-header.success-gradient { - background: linear-gradient(90deg, var(--success) 0%, var(--primary) 50%, var(--secondary) 100%); -} - -.terminal-header.warning-gradient { - background: linear-gradient(90deg, var(--warning) 0%, var(--accent) 50%, var(--primary) 100%); -} - -/* Terminal window controls */ -.terminal-controls { - display: flex; - align-items: center; - margin-bottom: 1rem; -} - -.window-dot { - width: 12px; - height: 12px; - border-radius: 50%; - margin-right: 8px; -} - -.window-dot.red { background: #ff5f56; } -.window-dot.yellow { background: #ffbd2e; } -.window-dot.green { - background: #27ca3f; - margin-right: 1rem; -} - -/* Monospace text styling */ -.mono-text { - font-size: 0.875rem; - color: var(--text-muted); -} - -/* Code block styling */ -.code-block { - margin: 0; - font-size: 0.9rem; - line-height: 1.6; - color: var(--text-primary); - background: none; -} - -/* Card components - using shared base styles */ -.component-card, -.success-card, -.enhancement-card { - padding: 1rem; - border-radius: var(--radius); - border: 1px solid var(--border); -} - -.component-card { - background: var(--surface-elevated); -} - -.success-card { - background: var(--success-bg); - border-color: var(--success-border); -} - -.enhancement-card { - color: var(--bg-color); - text-align: center; - border: none; -} - -/* Grid layouts - shared base properties */ -.components-grid, -.theme-grid, -.enhancements-grid, -.guidelines-grid { - display: grid; - gap: 1rem; -} - -.components-grid { - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - margin: 1rem 0; -} - -.theme-grid { - grid-template-columns: 1fr 1fr; - margin: 1rem 0; -} - -.enhancements-grid { - grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); -} - -.guidelines-grid { - gap: 0.5rem; -} - -/* Guideline items */ -.guideline-item { - display: flex; - align-items: center; - background: var(--surface-elevated); - padding: 1rem; - border-radius: var(--radius); - border-left: 4px solid; -} - -.guideline-icon { - font-size: 1.5rem; - margin-right: 1rem; -} - -/* Demo section styling */ -.demo-section { - padding: 4rem 0; - background: var(--bg-color); -} - -.demo-container { - max-width: 1200px; - margin: 0 auto; - padding: 0 1rem; - text-align: center; -} - -.demo-container h2 { - font-size: 2.5rem; - margin-bottom: 1rem; - background: linear-gradient(135deg, var(--primary), var(--secondary)); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.demo-container > p { - font-size: 1.25rem; - color: var(--text-secondary); - margin-bottom: 3rem; -} - -.demo-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(500px, 1fr)); - gap: 2rem; - margin-top: 3rem; -} - -.demo-card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-xl); - padding: 2.5rem; - box-shadow: var(--shadow-md); - text-align: left; -} - -.demo-card h3 { - margin-bottom: 2rem; - color: var(--text-primary); - text-align: center; -} - -.demo-form { - max-width: none; -} - -/* Flex layouts */ -.button-showcase, -.notification-demo { - display: flex; - gap: 1rem; -} - -.button-showcase { - flex-wrap: wrap; - margin-bottom: 2rem; - justify-content: center; -} - -.notification-demo { - flex-direction: column; -} - -/* Responsive design lol */ -@media (max-width: 768px) { - .demo-grid { - grid-template-columns: 1fr; - gap: 1.5rem; - } - - .demo-card { - padding: 2rem 1.5rem; - } - - .button-showcase { - flex-direction: column; - align-items: center; - } - - .button-showcase .btn { - width: 100%; - max-width: 250px; - } -} \ No newline at end of file diff --git a/site/info/uce-starter/views/page1.uce b/site/info/uce-starter/views/page1.uce deleted file mode 100644 index 0ee58c3..0000000 --- a/site/info/uce-starter/views/page1.uce +++ /dev/null @@ -1,59 +0,0 @@ -#load "../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Components"; - starter_register_css("views/marketing.css", context); - - <> -

Component System

-
-

Component Declaration

-
-
-
-
-
-
- marketing_blocks.uce -
-
COMPONENT:HERO_SECTION(Request& context)
-{
-    String title = first(context.call["title"].to_string(), "Welcome");
-    <>
-        <div class="hero-section">...</div>
-    </>
-}
-
-
- -
-

Example Components

-
-

marketing_blocks:HERO_SECTION

Landing page hero with CTA buttons

-

marketing_blocks:FEATURES_GRID

Feature showcase grid

-

widgets:DATA_TABLE

ag-Grid table wrapper

-

widgets:SORTABLE_TABLE

Lightweight sortable HTML table

-

primitives:APP_FRAME

Workspace shell wrapper

-

gauges:ARCGAUGE

SVG KPI gauge component

-
-
- -
-

Usage Examples

-
-
-
-
-
-
- views/index.uce -
-
DTree props;
-props["title"] = "Stunning Apps";
-<><?: component("example/marketing_blocks:HERO_SECTION", props, context) ?></>
-
-
- -} diff --git a/site/info/uce-starter/views/page2-section1.uce b/site/info/uce-starter/views/page2-section1.uce deleted file mode 100644 index c520b13..0000000 --- a/site/info/uce-starter/views/page2-section1.uce +++ /dev/null @@ -1,11 +0,0 @@ -#load "../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_type"] = "blank"; - <> - - Page 2 Section 1 loaded -
UCE starter AJAX fragment response
- -} diff --git a/site/info/uce-starter/views/page2.uce b/site/info/uce-starter/views/page2.uce deleted file mode 100644 index e1a571a..0000000 --- a/site/info/uce-starter/views/page2.uce +++ /dev/null @@ -1,25 +0,0 @@ -#load "../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Ajaxy"; - <> -

Ajax Demo

-
-

This is the content of Page 2. You can add more information here.

-

Sed at dolor leo. Morbi a tellus sed nisl dictum ultricies sit amet at purus. Nam mattis metus sed nunc egestas convallis.

-
- -
- - -} diff --git a/site/info/uce-starter/views/theme-preview.uce b/site/info/uce-starter/views/theme-preview.uce deleted file mode 100644 index d62ae54..0000000 --- a/site/info/uce-starter/views/theme-preview.uce +++ /dev/null @@ -1,69 +0,0 @@ -#load "../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Theme Preview"; - starter_register_css("views/themes.css", context); - String current_theme_key = context.cfg.get_by_path("theme/key").to_string(); - String theme_label = first(context.cfg.get_by_path("theme/label").to_string(), current_theme_key); - String theme_mode = context.cfg.get_by_path("theme/mode").to_string(); - StringMap theme_params; - theme_params["theme"] = current_theme_key; - - <> -
-
- Starter Theme Preview -

-

This route renders the same neutral content inside each theme so downstream projects can compare layout, typography, color tokens, and chrome.

- -
-
-
-

Tokens at a Glance

-
-
Current Theme
-
Mode
-
Preview Routetheme-preview
-
-
- Primary - Secondary - Accent - Surface -
-
-
-

System Message States

- - - -
-
-

Form Controls

-
-
-
-
-
-
-
-
-

Dense Content Block

- - - - - - - -
AreaExpectationStatus
NavigationShould remain readable when menus get long.Verified
CardsShould keep spacing and hierarchy on both desktop and mobile.Verified
EmbedsShould render cleanly inside the gallery iframe.Verified
-
-
-
- -} diff --git a/site/info/uce-starter/views/themes.css b/site/info/uce-starter/views/themes.css deleted file mode 100644 index aea3292..0000000 --- a/site/info/uce-starter/views/themes.css +++ /dev/null @@ -1,180 +0,0 @@ -.theme-gallery-shell, -.theme-preview-shell { - display: grid; - gap: 1.5rem; -} - -.theme-gallery-kicker, -.theme-preview-kicker { - display: inline-flex; - align-items: center; - gap: 0.5rem; - font-size: 0.82rem; - font-weight: 700; - letter-spacing: 0.08em; - text-transform: uppercase; - color: var(--text-secondary); - margin-bottom: 0.75rem; -} - -.theme-gallery-hero h1, -.theme-preview-hero h1 { - margin-bottom: 0.75rem; -} - -.theme-gallery-hero p, -.theme-preview-hero p { - max-width: 72ch; - color: var(--text-secondary); -} - -.theme-gallery-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); - gap: 1.25rem; -} - -.theme-gallery-card, -.theme-preview-card, -.theme-preview-hero { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius-lg, var(--radius)); - padding: 1.25rem; - box-shadow: var(--shadow-sm); -} - -.theme-gallery-card.is-active { - border-color: var(--primary); - box-shadow: 0 0 0 1px color-mix(in srgb, var(--primary) 35%, transparent 65%), var(--shadow-md); -} - -.theme-gallery-head { - display: flex; - justify-content: space-between; - align-items: flex-start; - gap: 1rem; - margin-bottom: 1rem; -} - -.theme-gallery-head p { - margin: 0.4rem 0 0; - color: var(--text-secondary); -} - -.theme-gallery-badge { - display: inline-flex; - align-items: center; - padding: 0.3rem 0.65rem; - border-radius: 999px; - background: color-mix(in srgb, var(--primary) 15%, transparent 85%); - color: var(--primary); - font-size: 0.78rem; - font-weight: 700; - white-space: nowrap; -} - -.theme-gallery-actions, -.theme-preview-actions { - display: flex; - flex-wrap: wrap; - gap: 0.75rem; - margin-bottom: 1rem; -} - -.theme-gallery-frame-wrap { - border: 1px solid var(--border); - border-radius: calc(var(--radius-lg, var(--radius)) - 4px); - overflow: hidden; - background: var(--bg-secondary); -} - -.theme-gallery-frame-wrap iframe { - display: block; - width: 100%; - height: 430px; - border: 0; - background: #fff; -} - -.theme-preview-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); - gap: 1rem; -} - -.theme-preview-stat-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); - gap: 0.75rem; - margin-bottom: 1rem; -} - -.theme-preview-stat { - display: grid; - gap: 0.2rem; - padding: 0.85rem; - border: 1px solid var(--border); - border-radius: var(--radius); - background: var(--surface-elevated, var(--bg-secondary)); -} - -.theme-preview-stat span { - font-size: 0.75rem; - font-weight: 700; - letter-spacing: 0.05em; - text-transform: uppercase; - color: var(--text-muted); -} - -.theme-preview-swatches { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); - gap: 0.75rem; -} - -.theme-preview-swatches span { - display: flex; - align-items: end; - min-height: 92px; - padding: 0.75rem; - border-radius: var(--radius); - color: #fff; - font-weight: 700; - box-shadow: inset 0 -20px 30px rgba(0, 0, 0, 0.12); -} - -.theme-preview-form { - max-width: none; - display: grid; - gap: 0.85rem; -} - -.embed-mode nav, -.embed-mode footer, -.embed-mode #theme-switcher, -.embed-mode .admin-toolbar { - display: none !important; -} - -.embed-mode #content, -.embed-mode .admin-content { - margin-top: 0 !important; - min-height: 100vh !important; - padding-top: 1rem !important; -} - -@media (max-width: 720px) { - .theme-gallery-grid, - .theme-preview-grid { - grid-template-columns: 1fr; - } - - .theme-gallery-head { - flex-direction: column; - } - - .theme-gallery-frame-wrap iframe { - height: 360px; - } -} \ No newline at end of file diff --git a/site/info/uce-starter/views/themes.uce b/site/info/uce-starter/views/themes.uce deleted file mode 100644 index 4a14a23..0000000 --- a/site/info/uce-starter/views/themes.uce +++ /dev/null @@ -1,46 +0,0 @@ -#load "../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Themes"; - starter_register_css("views/themes.css", context); - String current_theme = context.cfg.get_by_path("theme/key").to_string(); - - <> - - -} diff --git a/site/info/uce-starter/views/workspace/index.uce b/site/info/uce-starter/views/workspace/index.uce deleted file mode 100644 index 620bf31..0000000 --- a/site/info/uce-starter/views/workspace/index.uce +++ /dev/null @@ -1,134 +0,0 @@ -#load "../../lib/app.uce" - -RENDER(Request& context) -{ - starter_boot(context); - context.var["starter"]["page_title"] = "Workspace"; - String section = first(context.var["starter"]["route"]["param"].to_string(), "overview"); - if(section != "overview" && section != "projects" && section != "activity") - section = "overview"; - - String title = section == "projects" ? "Projects queue" : (section == "activity" ? "Recent activity" : "Workspace overview"); - String subtitle = section == "projects" ? "Nested path fallback lets one controller serve multiple panes cleanly." : (section == "activity" ? "Sidebar-first tools often need a live or recent-events pane." : "A generic app-shell pattern for tools, admin consoles, and internal products."); - String status_label = section == "projects" ? "3 active" : (section == "activity" ? "Monitoring" : "Ready"); - String status_variant = section == "projects" ? "info" : (section == "activity" ? "warn" : "success"); - String description = section == "projects" ? "This page is served from views/workspace/index.uce while the route remains workspace/projects." : (section == "activity" ? "The workspace shell is a better fit than the marketing-style home page when the app is navigation-heavy and stateful." : "This slice comes from the portal app: a reusable workspace shell with sidebar navigation, compact mobile controls, and semantic panel primitives."); - - String sidebar_body = ""; - ob_start(); - <> -
Workspace areas
- -

This sidebar and mobile shell pattern was extracted from the AI portal app and normalized against starter theme tokens.

- - sidebar_body = ob_get_close(); - DTree 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; - toolbar_props["action_html"] = "Open shell"; - 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; - 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; - 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; - 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; - header_props["title"] = title; - header_props["subtitle"] = subtitle; - header_props["actions_html"] = status_html; - String header = component("../../components/workspace/primitives:PANEL_HEADER", header_props, context); - - String stats_html = ""; - ob_start(); - <> -
-
Sidebar pattern
Responsive
Overlay on mobile
-
Routing mode
Nested
Parent-path fallback
-
Source app
uh-ai
Portal shell
-
- - stats_html = ob_get_close(); - - String detail_html = ""; - ob_start(); - <> -
-

Shell layout

Sidebar plus main panel, responsive overlay behavior, and a compact mobile header.

-

Semantic primitives

Panels, section heads, status pills, list states, and empty-state placeholders.

-

Starter-friendly

Backported against the starter theme variables instead of portal-specific branding tokens.

-
- - detail_html = ob_get_close(); - - DTree 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; - section_props["header_html"] = why_head; - section_props["body_html"] = "

" + html_escape(description) + "

" + stats_html; - String main_body = component("../../components/workspace/primitives:SECTION", section_props, context); - - section_head.clear(); - section_head["title"] = "Starter demo content"; - String demo_head = component("../../components/workspace/primitives:SECTION_HEAD", section_head, context); - section_props.clear(); - section_props["header_html"] = demo_head; - section_props["body_html"] = detail_html + "

Try visiting " + html_escape(starter_link("workspace/projects", context)) + " or " + html_escape(starter_link("workspace/activity", context)) + " to see the nested route fallback in action.

"; - main_body += component("../../components/workspace/primitives:SECTION", section_props, context); - - if(section == "activity") - { - DTree 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."; - empty_props["action_html"] = "Open dashboard demo"; - main_body += component("../../components/workspace/primitives:EMPTY_STATE", empty_props, context); - } - - DTree 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; - app_props["id"] = "workspace-demo-shell"; - app_props["overlay_id"] = "workspace-demo-overlay"; - app_props["sidebar_html"] = sidebar; - app_props["main_html"] = main; - print(component("../../components/workspace/primitives:APP_FRAME", app_props, context)); - <> - - -} diff --git a/site/tests/components.uce b/site/tests/components.uce index 1a2e041..f565bc0 100644 --- a/site/tests/components.uce +++ b/site/tests/components.uce @@ -23,6 +23,7 @@ RENDER(Request& context) bool exists = component_exists("components/panel"); String resolved = component_resolve("components/panel"); String panel_markup = component("components/panel", props, context); + String alias_markup = component("components/props_alias", props, context); ob_start(); component_render("components/panel:FOOTER", props, context); @@ -37,12 +38,14 @@ RENDER(Request& context) check("component_exists()", exists, exists ? "components/panel resolved as existing" : "components/panel missing"); check("component_resolve()", resolved != "", resolved); check("component()", panel_markup.find("Component Output") != String::npos && panel_markup.find("This body comes from component()") != String::npos, panel_markup); + check("COMPONENT(Request& props) alias", alias_markup.find("alias=Component Output") != String::npos && alias_markup.find("body=This body comes from component()") != String::npos, alias_markup); check("component_render() named handler", footer_markup.find("Named footer render") != String::npos, footer_markup); check("ob_start() / ob_get_close()", buffer_markup == "buffered-text", buffer_markup); ?>

Rendered Component

+
+ <>
} \ No newline at end of file diff --git a/site/tests/components/markdown/warning.uce b/site/tests/components/markdown/warning.uce index da19993..a7a9d4b 100644 --- a/site/tests/components/markdown/warning.uce +++ b/site/tests/components/markdown/warning.uce @@ -1,4 +1,4 @@ COMPONENT(Request& context) { - <>
+ <>
} \ No newline at end of file diff --git a/site/tests/components/panel.uce b/site/tests/components/panel.uce index 7f6f731..441a2bf 100644 --- a/site/tests/components/panel.uce +++ b/site/tests/components/panel.uce @@ -1,23 +1,23 @@ COMPONENT(Request& context) { <>
- - - + + +
} COMPONENT:HEADER(Request& context) { - <>

+ <>

} COMPONENT:BODY(Request& context) { - <>

+ <>

} COMPONENT:FOOTER(Request& context) { - <> + <> } \ No newline at end of file diff --git a/site/tests/components/props_alias.uce b/site/tests/components/props_alias.uce new file mode 100644 index 0000000..3fb988c --- /dev/null +++ b/site/tests/components/props_alias.uce @@ -0,0 +1,10 @@ +COMPONENT(Request& props) +{ + String title = props.props["title"].to_string(); + String body = props.props["body"].to_string(); + + <>
+ alias= +

body=

+
+} \ No newline at end of file diff --git a/site/tests/index.uce b/site/tests/index.uce deleted file mode 100644 index fa1e56e..0000000 --- a/site/tests/index.uce +++ /dev/null @@ -1,35 +0,0 @@ -#include "testlib.h" - -RENDER(Request& context) -{ - bool local_only = test_demo_request_allowed(context); - site_tests_page_start( - "Coverage Index", - "Grouped runtime coverage pages for the published site. Public-safe pages stay available everywhere; stateful or infrastructure-touching pages stay local-only." - ); - - if(local_only) - { - ?>
Local-network access detected. The full suite, including filesystem, service, and task coverage pages, is available.
Public access detected. Local-only pages remain linked here but will return a restricted message instead of mutating server state.
0) event_request.cookies = parse_cookies(event_request.params["HTTP_COOKIE"]); - event_request.var["ws"]["message"] = message; - event_request.var["ws"]["connection_id"] = event_request.resources.websocket_connection_id; - event_request.var["ws"]["scope"] = event_request.resources.websocket_scope; - event_request.var["ws"]["connection_count"] = (f64)event_request.resources.websocket_scope_connection_ids.size(); - event_request.var["ws"]["opcode"] = (f64)event_request.resources.websocket_opcode; - event_request.var["ws"]["is_binary"].set_bool(event_request.resources.websocket_is_binary); - event_request.var["ws"]["is_text"].set_bool(event_request.resources.websocket_is_text); - event_request.var["ws"]["document_uri"] = first( + event_request.params["WS_MESSAGE"] = message; + event_request.params["WS_CONNECTION_ID"] = event_request.resources.websocket_connection_id; + event_request.params["WS_SCOPE"] = event_request.resources.websocket_scope; + event_request.params["WS_CONNECTION_COUNT"] = (f64)event_request.resources.websocket_scope_connection_ids.size(); + event_request.params["WS_OPCODE"] = (f64)event_request.resources.websocket_opcode; + event_request.params["WS_MESSAGE_TYPE"] = (event_request.resources.websocket_is_binary ? "BINARY" : "TEXT"); + event_request.params["WS_DOCUMENT_URI"] = first( event_request.params["DOCUMENT_URI"], event_request.params["REQUEST_URI"] ); - event_request.call["message"] = message; - event_request.call["connection_id"] = event_request.resources.websocket_connection_id; - event_request.call["scope"] = event_request.resources.websocket_scope; - event_request.call["opcode"] = (f64)event_request.resources.websocket_opcode; - event_request.call["document_uri"] = event_request.var["ws"]["document_uri"].to_string(); return(event_request); } @@ -689,13 +683,6 @@ String normalize_ws_scope(String scope) return(expand_path(scope, cwd_get())); } -String ws_message() -{ - if(!context) - return(""); - return(context->call["message"].to_string()); -} - bool config_truthy(String raw, bool default_value = true) { raw = to_lower(trim(raw)); @@ -883,7 +870,7 @@ int handle_complete(FastCGIRequest& request) { } } - request.call = DTree(); + request.props = DTree(); compiler_invoke(&request, request.params["SCRIPT_FILENAME"]); } catch(const std::exception& e) diff --git a/tests/README.md b/tests/README.md index 6b1ffc4..50c3d89 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,6 +1,6 @@ # Network Tests -This directory contains a dependency-less vanilla Python 3 network test runner and plugin-style test cases. +This directory contains a dependency-less vanilla Python 3 network test runner and plugin-style test cases. These are AI-generated so they might be garbage. ## Runner