How Echo's header and footer are put together, why menus fit without JavaScript, how the Sass is organised, and where built and static assets come from. Read this before you override header or footer views or add CSS.
The header layout is the header_preset theme option. Each preset is one Blade file in resources/themes/echo/components/headers/, chosen by components/application-header.blade.php.
| Id | Layout |
|---|---|
logo-left | Classic: logo left, navigation right (default) |
centered | Logo on top, navigation below; optional search |
split | Navigation split around a centred logo |
pill | Floating, rounded, detached bar |
fullscreen | Minimal bar with a full-screen overlay menu |
commerce | Search-first, two tiers |
contact | Contact details card and a call to action |
tag | Logo on a tab hanging below the bar |
index | Numbered, ruled navigation cells |
Old ids stored in sites' options and page settings are mapped to current ones in application-header.blade.php (centered-split → split, offcanvas → fullscreen, utility-bar → contact, transparent-overlay → logo-left). Keep that map when you rename or remove a preset.
Every preset renders components/headers/partials/actions.blade.php: an account icon, a cart icon, then one filled call-to-action button (header_cta_label, header_cta_url), then the drawer button when the menu does not fit.
header_account hides it.App\Support\TopbarHtml::href(), which allows paths, #, http(s), mailto: and tel:, and rejects javascript:, data: and protocol-relative URLs.No JavaScript measures the menu. When a menu's cache is built, Menu::fitBucket() turns the top-level labels into a weight from 1 to Menu::FIT_OVERFLOW (characters, plus extra for each item, caret and icon). The header prints it as data-nav-fit, and _header.scss generates, per preset, the screen width at which a menu of that weight fits beside the logo and the action cluster. Below that width the drawer button shows; above FIT_OVERFLOW the menu always lives in the drawer.
.app-header__menu; do not add d-none d-lg-* to menu markup.reserved width in $header-fit-presets.--bs-header-bg, --bs-header-color, --bs-header-hover-color). Separate dropdown colours apply only when menu_color_mode is custom.The optional top bar (topbar_enabled) has a start and an end side. Each side is either text or a menu (topbar_start_type, topbar_end_type), never widgets. Text passes through TopbarHtml::clean(), which keeps only i, span, strong, b and a, before it is printed unescaped; menus render top-level items only through menu/topbar.blade.php.
footer-1 to footer-6; the number of columns is footer_widget_columns.footer_layout): columns, wide-brand, centered, banner, wide-end, two-up, lead-stack, cards, ruled.footer_background_type): solid colour, gradient or image, with an optional overlay.footer_shape): none, skyline, treeline, hills, torn, bubbles, stairs, equalizer, halftone, stamp, meadow, sunrise, in three sizes.resources/themes/echo/assets/sass/
app.scss entry: Bootstrap with Echo's variables, then Echo's layers below
app-editor.scss a scoped copy for the page-builder canvas
_variables.scss Bootstrap variable overrides (Echo's spacer scale is custom)
global.scss, _mixin.scss, _animations.scss, _dark-mode.scss, _rtl.scss
components/ header, footer, nav, buttons, forms, widgets, publication (blog), page sections ...
layout/ pages/ utilities/ widgets/
kit/ the ui-* section kit used by template-library layoutsmb-5 is 2.5rem and mb-6 exists). Check _variables.scss before assuming sizes..css files stored in the database, and the shared ui-* kit is built with npm run templates:kit. See Template library.var(--bs-primary), not a hex value, so theme options keep working.All front-end code is built by one Vite configuration at the project root. Every entry point, including those of bundled modules, is listed in its input array:
| Entry | Loaded by |
|---|---|
resources/themes/echo/assets/sass/app.scss, app-editor.scss, assets/js/app.js | Echo layouts; the editor canvas |
resources/themes/admin/assets/sass/app.scss, assets/js/app.js, page-builder.js, GrapesJS styles | Admin layout and page builder |
resources/themes/echo/page-templates/scripts/motion.js, widgets.js | Only pages that contain a section needing them |
Modules/{Booking,TruCommerce,TruPayments}/resources/... | Each module's admin and front layouts, via @vite() |
npm run build # production build into public/build
npm run dev # dev server with hot reload
npm run templates:kit # rebuild the ui-* section kit CSS stored for the template libraryAfter a build that changes Echo's styles, regenerate the theme CSS (see How options become CSS). The full build reference, including how a plugin ships its own assets, is in Build and assets.
resources/themes/{theme}/assets/images and are copied by Vite to public/themes/{theme}. Reference them with theme_url('/themes/echo/images/...') or asset().public/modules/{folder} the same way (note TruCommerce's folder is tru-commerce).ph ph-{name}, ph-fill ph-{name}), bundled into Echo's CSS.storage/.