laika-framework

Assets, Meta & Navigation

Helpers for the parts of a page that aren’t the view itself: stylesheets and scripts, meta tags, request-wide template data, menus and icons.

Styles and Scripts

Queue assets anywhere — template/loader.php, a controller, a hook — and print them in the layout.

// template/loader.php
enqueue_style('bootstrap', 'assets/css/bootstrap.min.css', '5.3.0');
enqueue_style('app', 'assets/css/app.css');
enqueue_script('app', 'assets/js/app.js', '1.0.0', defer: true);
<head>
    {{ 'lf_header'|hook }}   {# metas + styles + the TOKEN and APP_URI JS constants #}
</head>
<body>
    ...
    {{ 'lf_footer'|hook }}   {# scripts #}
</body>
Helper Relay method (Laika\Engine\Services\Asset)
enqueue_style(string $handle, string $src, string $version = '', string $media = 'all'): void addStyle(...)
enqueue_script(string $handle, string $src, string $version = '', bool $defer = false): void addScript(...)
print_styles(): void / print_scripts(): void printStyles() / printScripts()
lf_header(): void Metas, styles, then headerScripts()
lf_footer(): void Scripts

asset(string $path): string returns the absolute URL of a file: <img src="{{ 'assets/img/logo.png'|asset }}"> → https://example.com/assets/img/logo.png?v=6a060148.

The ?v= is the file’s modification time, which is what lets the response be cached immutably instead of revalidated on every page load. It is added only for a file that exists under the project root — a path that resolves to nothing gets no version rather than a made-up one, and a URL that already has a host is returned untouched.

Meta Tags

enqueue_meta('description', 'Invoices and payments for your team');
enqueue_meta('og:title', 'Laika Billing', 'property');
Helper / method  
enqueue_meta(string $name, string $content, string $type = 'name'): void / Meta::add(...) <meta name="…">, or property="…" for Open Graph. The same name replaces the earlier tag.
print_metas(): void / Meta::print() Print them, HTML-escaped (also done by lf_header())

Context — Data for Every Template

Laika\Engine\Services\Context is a request-wide key/value store. Anything set there — from a pipeline, a hook, a service — reaches every template as {{ context }}.

// in a pipeline
context_add('user', $user);
context_add('unread', $notifications->unreadCount());
Hello {{ context.user.first_name }} — {{ 'unread'|context }} new messages
Helper / method  
context_add(string $key, mixed $value): void / Context::set(...) Store a value
context_get(?string $key = null, mixed $default = null): mixed / Context::get(...) One value, or everything
Context::has(string $key): bool / Context::pop(string $key): void / Context::clear(): void Manage keys

Keys must match \w+ and are lowercased; anything else throws ContextException.

Page Title

page_title(string $title): string returns "{$title} | {app name}". In Twig: {{ 'page_title'|hook(title) }}. Hook callbacks you add to page_title run before the core one, so you can rewrite the title first.

Laika\Engine\Services\Nav builds menus from named routes and marks the active item from the current URL.

// e.g. in a pipeline or hook file
use Laika\Engine\Services\Nav;

Nav::add('Dashboard', 'dashboard')->icon('bi bi-speedometer');
Nav::add('Orders', 'orders.index')
    ->child('All orders', 'orders.index')->end()
    ->child('Refunds', 'orders.refunds', display: Session::get('role') === 'admin');
// in the controller or template
echo Nav::render('navbar');
Nav method  
add(string $title, string $named, array $namedParams = [], bool $display = true): Item A top-level item
configure(array $config): static Renderer settings (classes, markup)
current(?string $url): static Override the URL used to detect the active item
find(string $name): ?Item / extend(string $name, callable $callback): static Look up / extend a named item
render(string $class = 'navbar'): string The menu HTML
items(): array / flush(): static Raw items / start over

An Item has child()/end() for nesting, name(), icon() (a CSS class) or svg() (inline SVG), addClass(), setId(), attr(), target(), rel() and active(). match_url(string $named): bool tells you whether the current URL is under a named route — handy for hand-built menus.

The full guide — active-state rules, conditional display, styling — is in the Nav README.

Icons

Laika\Engine\Generator\Icon returns inline SVG (Bootstrap Icons path data). Nothing is loaded from a CDN, and icons inherit the text colour.

use Laika\Engine\Generator\Icon;

Icon::svg('trash', 20);    // <svg … width="20" height="20">…</svg>
Icon::trash(20);           // the same, through the magic method
Icon::has('rocket');       // false
Icon::names();             // every available name

svg(string $name, int $size = 16): string clamps the size to 8–128; an unknown name falls back to info. Available names include arrow-left/right/up/down, plus, edit, trash, save, search, refresh, download, printer, check, cross, ban, info, warning, eye, user, staff, key, login, logout, dashboard, reports, orders, products, invoices, currency, card, database, settings, mail, calendar, folder, menu and more.

Twig escapes filter output, so register the filter yourself and mark it raw:

$tpl->addFilter('icon', [\Laika\Engine\Generator\Icon::class, 'svg']);
<button>{{ 'trash'|icon(14)|raw }} Delete</button>

See Also