06177dc3e1
Repo Health / Access control (push) Successful in 1s
Repo Health / Scripts governance (push) Successful in 3s
Repo Health / Release configuration (push) Failing after 3s
Repo Health / Repository health (push) Failing after 3s
Update Joomla Update Server XML Feed / Update updates.xml (push) Successful in 10s
Remove custom_head_start/custom_head_end template params and associated code from index.php, error.php, and templateDetails.xml in favor of the existing user.js and user.css asset loading (via Web Asset Manager). Add dedicated component.css for the print/component view that replaces template.css with print-optimized styles using theme variables. Component view now loads custom light palette when configured and sends a content_group=print_view identifier to Google Analytics. Add user.css and user.js to .gitignore (client-repo only files). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
634 lines
24 KiB
PHP
634 lines
24 KiB
PHP
<?php
|
|
/* Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
|
|
|
|
This file is part of a Moko Consulting project.
|
|
|
|
SPDX-License-Identifier: GPL-3.0-or-later
|
|
*/
|
|
|
|
|
|
defined('_JEXEC') or die;
|
|
|
|
// One-time migration from MokoCassiopeia (runs once, creates .migrated marker)
|
|
if (!file_exists(__DIR__ . '/.migrated')) {
|
|
require_once __DIR__ . '/helper/migrate.php';
|
|
}
|
|
|
|
use Joomla\CMS\Factory;
|
|
use Joomla\CMS\HTML\HTMLHelper;
|
|
use Joomla\CMS\Language\Text;
|
|
use Joomla\CMS\Uri\Uri;
|
|
use Joomla\CMS\Component\ComponentHelper;
|
|
|
|
/** @var Joomla\CMS\Document\HtmlDocument $this */
|
|
|
|
$app = Factory::getApplication();
|
|
$input = $app->getInput();
|
|
$document = $app->getDocument();
|
|
$wa = $document->getWebAssetManager();
|
|
|
|
// Template params
|
|
$params_LightColorName = (string) $this->params->get('colorLightName', 'standard'); // standard|custom
|
|
|
|
$params_DarkColorName = (string) $this->params->get('colorDarkName', 'standard'); // standard|custom
|
|
|
|
$params_googletagmanager = $this->params->get('googletagmanager', false);
|
|
$params_googletagmanagerid = $this->params->get('googletagmanagerid', null);
|
|
$params_googleanalytics = $this->params->get('googleanalytics', false);
|
|
$params_googleanalyticsid = $this->params->get('googleanalyticsid', null);
|
|
$params_googlesitekey = $this->params->get('googlesitekey', null);
|
|
$params_visitordetection = $this->params->get('googlevisitordetection', true);
|
|
$params_developmentmode = $this->params->get('developmentmode', false) || $app->get('debug', false);
|
|
$params_favicon_source = (string) $this->params->get('favicon_source', '');
|
|
|
|
// Theme params
|
|
$params_theme_enabled = $this->params->get('theme_enabled', 1);
|
|
$params_theme_control_type = (string) $this->params->get('theme_control_type', 'radios');
|
|
$params_theme_fab_enabled = $this->params->get('theme_fab_enabled', 1);
|
|
$params_theme_fab_pos = 'br';
|
|
|
|
// Accessibility params
|
|
$params_a11y_toolbar = $this->params->get('a11y_toolbar_enabled', 1);
|
|
$params_a11y_resize = $this->params->get('a11y_text_resize', 1);
|
|
$params_a11y_invert = $this->params->get('a11y_color_inversion', 1);
|
|
$params_a11y_contrast = $this->params->get('a11y_high_contrast', 1);
|
|
$params_a11y_links = $this->params->get('a11y_highlight_links', 1);
|
|
$params_a11y_font = $this->params->get('a11y_readable_font', 1);
|
|
$params_a11y_animations = $this->params->get('a11y_pause_animations', 1);
|
|
$params_a11y_pos = 'br';
|
|
|
|
// Detecting Active Variables
|
|
$option = $input->getCmd('option', '');
|
|
$view = $input->getCmd('view', '');
|
|
$layout = $input->getCmd('layout', '');
|
|
$task = $input->getCmd('task', '');
|
|
$itemid = $input->getCmd('Itemid', '');
|
|
$sitenameR = $app->get('sitename'); // raw for title composition
|
|
$sitename = htmlspecialchars($sitenameR, ENT_QUOTES, 'UTF-8');
|
|
$menu = $app->getMenu()->getActive();
|
|
$pageclass = $menu !== null ? $menu->getParams()->get('pageclass_sfx', '') : '';
|
|
|
|
// Template/Media path
|
|
$templatePath = 'media/templates/site/mokoonyx';
|
|
|
|
// Favicon generation
|
|
$faviconHeadTags = '';
|
|
if ($params_favicon_source) {
|
|
require_once __DIR__ . '/helper/favicon.php';
|
|
// Joomla's media field returns paths like:
|
|
// 'images/logo.png' (images folder)
|
|
// 'media/templates/site/mokoonyx/images/logo.png' (template media)
|
|
// 'logo.png' (bare filename)
|
|
// Strip Joomla's #joomlaImage:// fragment from media field value
|
|
$faviconSourceRel = strtok(ltrim($params_favicon_source, '/'), '#');
|
|
$faviconSourceAbs = JPATH_ROOT . '/' . $faviconSourceRel;
|
|
// Try common prefixes if not found
|
|
if (!is_file($faviconSourceAbs)) {
|
|
$candidates = [
|
|
JPATH_ROOT . '/images/' . $faviconSourceRel,
|
|
JPATH_ROOT . '/media/templates/site/' . $this->template . '/' . $faviconSourceRel,
|
|
JPATH_ROOT . '/media/templates/site/' . $this->template . '/images/' . basename($faviconSourceRel),
|
|
];
|
|
foreach ($candidates as $candidate) {
|
|
if (is_file($candidate)) {
|
|
$faviconSourceAbs = $candidate;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
$faviconOutputDir = JPATH_ROOT . '/media/templates/site/' . $this->template . '/images/favicons';
|
|
$faviconUrlBase = Uri::root(true) . '/media/templates/site/' . $this->template . '/images/favicons';
|
|
|
|
if (MokoFaviconHelper::generate($faviconSourceAbs, $faviconOutputDir)) {
|
|
$faviconHeadTags = MokoFaviconHelper::getHeadTags($faviconUrlBase);
|
|
}
|
|
}
|
|
|
|
// Minification: dev mode ON → delete .min files; OFF → regenerate if stale
|
|
require_once __DIR__ . '/helper/minify.php';
|
|
MokoMinifyHelper::sync(JPATH_ROOT . '/' . $templatePath, (bool) $params_developmentmode);
|
|
|
|
// Core template CSS + JS — Joomla auto-serves .min when debug is off
|
|
$wa->useStyle('template.base'); // css/template.css (or .min.css)
|
|
$wa->useScript('template.js'); // js/template.js (or .min.js)
|
|
|
|
// Load Osaka font for site title
|
|
$wa->useStyle('template.font.osaka');
|
|
|
|
// Load GTM script if GTM is enabled
|
|
if (!empty($params_googletagmanager) && !empty($params_googletagmanagerid)) {
|
|
$wa->useScript('gtm.js');
|
|
}
|
|
|
|
/**
|
|
* VirtueMart detection:
|
|
* - Component must exist and be enabled
|
|
*/
|
|
$isVirtueMartActive = ComponentHelper::isEnabled('com_virtuemart', true);
|
|
|
|
if ($isVirtueMartActive) {
|
|
/**
|
|
* Load a VirtueMart-specific stylesheet defined in your template manifest.
|
|
* This assumes you defined an asset named "template.virtuemart".
|
|
*/
|
|
$wa->useStyle('vendor.vm');
|
|
}
|
|
|
|
// Font scheme (external or local) + CSS custom properties
|
|
$params_FontScheme = $this->params->get('useFontScheme', false);
|
|
$fontStyles = '';
|
|
|
|
if ($params_FontScheme) {
|
|
if (stripos($params_FontScheme, 'https://') === 0) {
|
|
$this->getPreloadManager()->preload($params_FontScheme, ['as' => 'style', 'crossorigin' => 'anonymous']);
|
|
$wa->registerAndUseStyle('fontscheme.current', $params_FontScheme, [], [
|
|
'media' => 'print',
|
|
'rel' => 'lazy-stylesheet',
|
|
'onload' => 'this.media=\'all\'',
|
|
'crossorigin' => 'anonymous'
|
|
]);
|
|
|
|
if (preg_match_all('/family=([^?:]*):/i', $params_FontScheme, $matches) > 0) {
|
|
$fontStyles = '--font-family-body: "' . str_replace('+', ' ', $matches[1][0]) . '", sans-serif;' . "\n";
|
|
$fontStyles .= '--font-family-headings: "' . str_replace('+', ' ', isset($matches[1][1]) ? $matches[1][1] : $matches[1][0]) . '", sans-serif;' . "\n";
|
|
$fontStyles .= '--font-weight-normal: 400;' . "\n";
|
|
$fontStyles .= '--font-weight-headings: 700;';
|
|
}
|
|
} else {
|
|
$wa->registerAndUseStyle('fontscheme.current', $params_FontScheme, ['version' => 'auto'], [
|
|
'media' => 'print',
|
|
'rel' => 'lazy-stylesheet',
|
|
'onload' => 'this.media=\'all\''
|
|
]);
|
|
$this->getPreloadManager()->preload(
|
|
$wa->getAsset('style', 'fontscheme.current')->getUri() . '?' . $this->getMediaVersion(),
|
|
['as' => 'style']
|
|
);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------
|
|
// Brand: logo from params OR siteTitle
|
|
// -------------------------------------
|
|
$brandHtml = '';
|
|
$logoFile = (string) $this->params->get('logoFile');
|
|
|
|
if ($logoFile !== '') {
|
|
$brandHtml = HTMLHelper::_(
|
|
'image',
|
|
Uri::root(false) . htmlspecialchars($logoFile, ENT_QUOTES, 'UTF-8'),
|
|
$sitename,
|
|
['class' => 'logo d-inline-block', 'loading' => 'eager', 'decoding' => 'async'],
|
|
false,
|
|
0
|
|
);
|
|
} else {
|
|
// If no logo file, show the title (defaults to "MokoOnyx" if not set)
|
|
$siteTitle = $this->params->get('siteTitle', 'MokoOnyx');
|
|
$brandHtml = '<span class="site-title" title="' . $sitename . '">'
|
|
. htmlspecialchars($siteTitle, ENT_COMPAT, 'UTF-8')
|
|
. '</span>';
|
|
}
|
|
|
|
// Layout flags
|
|
$hasClass = '';
|
|
if ($this->countModules('sidebar-left', true)) { $hasClass .= ' has-sidebar-left'; }
|
|
if ($this->countModules('sidebar-right', true)) { $hasClass .= ' has-sidebar-right'; }
|
|
if ($this->countModules('drawer-left', true)) { $hasClass .= ' has-drawer-left'; }
|
|
if ($this->countModules('drawer-right', true)) { $hasClass .= ' has-drawer-right'; }
|
|
|
|
// Smart Bootstrap component loading - only load what's needed
|
|
HTMLHelper::_('bootstrap.collapse');
|
|
if ($this->countModules('drawer-left', true) || $this->countModules('drawer-right', true)) {
|
|
HTMLHelper::_('bootstrap.offcanvas');
|
|
}
|
|
|
|
// Container
|
|
$wrapper = $this->params->get('fluidContainer') ? 'wrapper-fluid' : 'wrapper-static';
|
|
$stickyHeader = $this->params->get('stickyHeader') ? 'position-sticky sticky-top' : '';
|
|
|
|
// Meta
|
|
$this->setMetaData('viewport', 'width=device-width, initial-scale=1');
|
|
if (!empty($params_googlesitekey)) {
|
|
$this->setMetaData('google-site-verification', htmlspecialchars($params_googlesitekey, ENT_QUOTES, 'UTF-8'));
|
|
}
|
|
|
|
// Font Awesome 7 — Kit (CDN) or local files
|
|
$faKitCode = trim((string) $this->params->get('fA6KitCode', ''));
|
|
if ($faKitCode !== '') {
|
|
HTMLHelper::_('script', 'https://kit.fontawesome.com/' . $faKitCode . '.js', ['crossorigin' => 'anonymous']);
|
|
} else {
|
|
// Load local FA7 Free — all.css via WebAsset
|
|
// Resolve the actual filesystem path: media dir (Joomla install) or template dir (SFTP deploy)
|
|
$faCssFile = 'vendor/fa7free/css/all.min.css'; // vendor ships minified only
|
|
$faCandidates = [
|
|
$templatePath . '/' . $faCssFile, // media/templates/site/mokoonyx/...
|
|
'templates/site/' . $this->template . '/media/' . $faCssFile, // templates/site/mokoonyx/media/...
|
|
];
|
|
|
|
// Also check via __DIR__ for edge cases
|
|
$faFromDir = __DIR__ . '/media/' . $faCssFile;
|
|
if (is_file($faFromDir)) {
|
|
$faCandidates[] = ltrim(str_replace('\\', '/', str_replace(JPATH_ROOT, '', $faFromDir)), '/');
|
|
}
|
|
|
|
$faRegistered = false;
|
|
foreach ($faCandidates as $faPath) {
|
|
if (is_file(JPATH_ROOT . '/' . $faPath)) {
|
|
$wa->registerStyle('vendor.fa7free.all', $faPath);
|
|
$faRegistered = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Use the asset — either our dynamic registration or the one from joomla.asset.json
|
|
try {
|
|
$wa->useStyle('vendor.fa7free.all');
|
|
} catch (\Throwable $e) {
|
|
// All paths exhausted — FA icons will rely on the IcoMoon compat layer
|
|
}
|
|
}
|
|
$params_leftIcon = htmlspecialchars($this->params->get('drawerLeftIcon', 'fa-solid fa-chevron-left'), ENT_COMPAT, 'UTF-8');
|
|
$params_rightIcon = htmlspecialchars($this->params->get('drawerRightIcon', 'fa-solid fa-chevron-right'), ENT_COMPAT, 'UTF-8');
|
|
|
|
// Load theme palette stylesheets — Joomla auto-serves .min when debug is off
|
|
$wa->useStyle('template.light.standard');
|
|
$wa->useStyle('template.dark.standard');
|
|
|
|
// Load custom palettes only if selected in template configuration AND files exist
|
|
if ($params_LightColorName === 'custom' && file_exists(JPATH_ROOT . '/media/templates/site/mokoonyx/css/theme/light.custom.css'))
|
|
{
|
|
$wa->useStyle('template.light.custom');
|
|
}
|
|
if ($params_DarkColorName === 'custom' && file_exists(JPATH_ROOT . '/media/templates/site/mokoonyx/css/theme/dark.custom.css'))
|
|
{
|
|
$wa->useStyle('template.dark.custom');
|
|
}
|
|
|
|
// Load user assets last (after all other styles and scripts)
|
|
$wa->useStyle('template.user'); // css/user.css
|
|
$wa->useScript('user.js'); // js/user.js
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
|
|
<head>
|
|
<jdoc:include type="head" />
|
|
<?php if ($faviconHeadTags) : ?>
|
|
<?php echo $faviconHeadTags; ?>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($params_theme_enabled) : ?>
|
|
<script>
|
|
// Early theme application to avoid FOUC
|
|
(function () {
|
|
try {
|
|
var stored = localStorage.getItem('theme');
|
|
var prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
var theme = stored ? stored : (prefersDark ? 'dark' : 'light');
|
|
document.documentElement.setAttribute('data-bs-theme', theme);
|
|
document.documentElement.setAttribute('data-aria-theme', theme);
|
|
} catch (e) {}
|
|
})();
|
|
</script>
|
|
<?php endif; ?>
|
|
|
|
<script>
|
|
// Facebook in-app browser warning banner
|
|
window.addEventListener('DOMContentLoaded', function () {
|
|
var ua = navigator.userAgent || navigator.vendor || window.opera;
|
|
var isFacebookBrowser = ua.indexOf('FBAN') > -1 || ua.indexOf('FBAV') > -1;
|
|
if (isFacebookBrowser) {
|
|
var warning = document.createElement('div');
|
|
warning.textContent = '⚠️ KNOWN ISSUE: Images do not load in Facebook Web browser. Please open in external browser for full experience.';
|
|
warning.style.position = 'fixed';
|
|
warning.style.top = '0';
|
|
warning.style.left = '0';
|
|
warning.style.right = '0';
|
|
warning.style.zIndex = '10000';
|
|
warning.style.backgroundColor = '#007bff';
|
|
warning.style.color = '#fff';
|
|
warning.style.padding = '15px';
|
|
warning.style.textAlign = 'center';
|
|
warning.style.fontWeight = 'bold';
|
|
warning.style.fontSize = '16px';
|
|
warning.style.boxShadow = '0 2px 5px rgba(0,0,0,0.2)';
|
|
document.body.appendChild(warning);
|
|
}
|
|
});
|
|
</script>
|
|
|
|
|
|
</head>
|
|
<body data-bs-spy="scroll" data-bs-target="#toc"
|
|
data-theme-fab-enabled="<?php echo $params_theme_fab_enabled ? '1' : '0'; ?>"
|
|
data-theme-fab-pos="<?php echo htmlspecialchars($params_theme_fab_pos, ENT_QUOTES, 'UTF-8'); ?>"
|
|
data-a11y-toolbar="<?php echo $params_a11y_toolbar ? '1' : '0'; ?>"
|
|
data-a11y-resize="<?php echo $params_a11y_resize ? '1' : '0'; ?>"
|
|
data-a11y-invert="<?php echo $params_a11y_invert ? '1' : '0'; ?>"
|
|
data-a11y-contrast="<?php echo $params_a11y_contrast ? '1' : '0'; ?>"
|
|
data-a11y-links="<?php echo $params_a11y_links ? '1' : '0'; ?>"
|
|
data-a11y-font="<?php echo $params_a11y_font ? '1' : '0'; ?>"
|
|
data-a11y-animations="<?php echo $params_a11y_animations ? '1' : '0'; ?>"
|
|
data-a11y-pos="<?php echo htmlspecialchars($params_a11y_pos, ENT_QUOTES, 'UTF-8'); ?>"
|
|
class="site <?php
|
|
echo $option . ' ' . $wrapper
|
|
. ' view-' . $view
|
|
. ($layout ? ' layout-' . $layout : ' no-layout')
|
|
. ($task ? ' task-' . $task : ' no-task')
|
|
. ($itemid ? ' itemid-' . $itemid : '')
|
|
. ($pageclass ? ' ' . $pageclass : '')
|
|
. $hasClass
|
|
. ($this->direction == 'rtl' ? ' rtl' : '');
|
|
?>">
|
|
<?php if (!empty($params_visitordetection) && (!empty($params_googletagmanager) || !empty($params_googleanalytics))) :
|
|
$user = Factory::getUser();
|
|
$visitorType = $user->guest ? 'guest' : 'logged_in';
|
|
$visitorGroup = 'none';
|
|
if (!$user->guest) {
|
|
$groupIds = $user->getAuthorisedGroups();
|
|
if (!empty($groupIds)) {
|
|
$db = Factory::getContainer()->get(\Joomla\Database\DatabaseInterface::class);
|
|
$query = $db->getQuery(true)
|
|
->select($db->quoteName('title'))
|
|
->from($db->quoteName('#__usergroups'))
|
|
->where($db->quoteName('id') . ' = ' . (int) end($groupIds));
|
|
$db->setQuery($query);
|
|
$visitorGroup = $db->loadResult() ?: 'unknown';
|
|
}
|
|
}
|
|
$pageType = $option . ($view ? '.' . $view : '');
|
|
?>
|
|
<!-- Smart Visitor Detection -->
|
|
<script>
|
|
window.dataLayer = window.dataLayer || [];
|
|
window.dataLayer.push({
|
|
'event': 'moko.visitor_detect',
|
|
'visitor_type': '<?php echo $visitorType; ?>',
|
|
'visitor_group': '<?php echo htmlspecialchars($visitorGroup, ENT_QUOTES, 'UTF-8'); ?>',
|
|
'page_type': '<?php echo htmlspecialchars($pageType, ENT_QUOTES, 'UTF-8'); ?>'
|
|
});
|
|
</script>
|
|
<!-- End Smart Visitor Detection -->
|
|
<?php endif; ?>
|
|
|
|
<?php if (!empty($params_googletagmanager) && !empty($params_googletagmanagerid)) :
|
|
$gtmID = htmlspecialchars($params_googletagmanagerid, ENT_QUOTES, 'UTF-8'); ?>
|
|
<!-- Google Tag Manager -->
|
|
<script>
|
|
(function(w,d,s,l,i){
|
|
w[l]=w[l]||[];
|
|
w[l].push({'gtm.start': new Date().getTime(), event:'gtm.js'});
|
|
var f=d.getElementsByTagName(s)[0],
|
|
j=d.createElement(s),
|
|
dl=l!='dataLayer'?'&l='+l:'';
|
|
j.async=true;
|
|
j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;
|
|
f.parentNode.insertBefore(j,f);
|
|
})(window,document,'script','dataLayer','<?php echo $gtmID; ?>');
|
|
</script>
|
|
<!-- End Google Tag Manager -->
|
|
|
|
<!-- Google Tag Manager (noscript) -->
|
|
<noscript>
|
|
<iframe src="https://www.googletagmanager.com/ns.html?id=<?php echo $gtmID; ?>"
|
|
height="0" width="0" style="display:none;visibility:hidden"></iframe>
|
|
</noscript>
|
|
<!-- End Google Tag Manager (noscript) -->
|
|
<?php endif; ?>
|
|
|
|
<?php if (!empty($params_googleanalytics) && !empty($params_googleanalyticsid)) :
|
|
$gaId = htmlspecialchars($params_googleanalyticsid, ENT_QUOTES, 'UTF-8'); ?>
|
|
<!-- Google Analytics (gtag.js) -->
|
|
<script async src="https://www.googletagmanager.com/gtag/js?id=<?php echo $gaId; ?>"></script>
|
|
<script>
|
|
window.dataLayer = window.dataLayer || [];
|
|
function gtag(){dataLayer.push(arguments);}
|
|
gtag('js', new Date());
|
|
gtag('consent', 'default', {
|
|
'ad_storage': 'denied',
|
|
'analytics_storage': 'granted',
|
|
'ad_user_data': 'denied',
|
|
'ad_personalization': 'denied'
|
|
});
|
|
(function(id){
|
|
if (/^G-/.test(id)) {
|
|
gtag('config', id, { 'anonymize_ip': true });
|
|
} else if (/^UA-/.test(id)) {
|
|
gtag('config', id, { 'anonymize_ip': true });
|
|
console.warn('Using a UA- ID. Universal Analytics is sunset; consider migrating to GA4.');
|
|
} else {
|
|
console.warn('Unrecognized Google Analytics ID format:', id);
|
|
}
|
|
})('<?php echo $gaId; ?>');
|
|
<?php if (!empty($params_visitordetection)) : ?>
|
|
gtag('set', 'user_properties', {
|
|
'visitor_type': '<?php echo $user->guest ? 'guest' : 'logged_in'; ?>',
|
|
'visitor_group': '<?php echo htmlspecialchars($visitorGroup ?? 'none', ENT_QUOTES, 'UTF-8'); ?>'
|
|
});
|
|
<?php endif; ?>
|
|
</script>
|
|
<!-- End Google Analytics -->
|
|
<?php endif; ?>
|
|
|
|
<header id="top" class="header container-header full-width<?php echo $stickyHeader ? ' ' . $stickyHeader : ''; ?>" role="banner">
|
|
|
|
<?php if ($this->countModules('topbar')) : ?>
|
|
<div class="container-topbar">
|
|
<jdoc:include type="modules" name="topbar" style="none" />
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="header-top">
|
|
<?php if ($this->countModules('below-topbar')) : ?>
|
|
<div class="grid container-below-topbar">
|
|
<jdoc:include type="modules" name="below-topbar" style="none" />
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($this->params->get('brand', 1)) : ?>
|
|
<div class="grid-child header-brand-wrap">
|
|
<div class="navbar-brand">
|
|
<a class="brand-logo" href="<?php echo $this->baseurl; ?>/">
|
|
<?php echo $brandHtml; ?>
|
|
</a>
|
|
<?php if ($this->params->get('siteDescription')) : ?>
|
|
<div class="site-description">
|
|
<?php echo htmlspecialchars($this->params->get('siteDescription'), ENT_QUOTES, 'UTF-8'); ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php if ($this->countModules('brand-aside', true)) : ?>
|
|
<div class="container-brand-aside">
|
|
<jdoc:include type="modules" name="brand-aside" style="card" />
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($this->countModules('below-logo')) : ?>
|
|
<div class="grid container-below-logo">
|
|
<jdoc:include type="modules" name="below-logo" style="none" />
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<!-- Drawer Toggle Buttons -->
|
|
<?php if ($this->countModules('drawer-left')) : ?>
|
|
<button class="drawer-toggle-left btn btn-outline-secondary me-2"
|
|
type="button"
|
|
data-bs-toggle="offcanvas"
|
|
data-bs-target="#drawer-left"
|
|
aria-controls="drawer-left">
|
|
<span class="<?php echo $params_leftIcon; ?>"></span>
|
|
</button>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($this->countModules('drawer-right')) : ?>
|
|
<button class="drawer-toggle-right btn btn-outline-secondary"
|
|
type="button"
|
|
data-bs-toggle="offcanvas"
|
|
data-bs-target="#drawer-right"
|
|
aria-controls="drawer-right">
|
|
<span class="<?php echo $params_rightIcon; ?>"></span>
|
|
</button>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($this->countModules('menu', true) || $this->countModules('search', true)) : ?>
|
|
<div class="grid-child container-nav">
|
|
<?php // Mobile: hamburger (left) + search icon (right) on one line ?>
|
|
<div class="nav-mobile-bar d-lg-none">
|
|
<?php if ($this->countModules('menu', true)) : ?>
|
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#moko-main-menu-collapse" aria-controls="moko-main-menu-collapse" aria-expanded="false" aria-label="<?php echo Text::_('JTOGGLE_NAVIGATION'); ?>">
|
|
<span class="fa-solid fa-bars" aria-hidden="true"></span>
|
|
</button>
|
|
<?php endif; ?>
|
|
<?php if ($this->countModules('search', true)) : ?>
|
|
<button class="search-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#headerSearchCollapse" aria-controls="headerSearchCollapse" aria-expanded="false" aria-label="<?php echo Text::_('JSEARCH_FILTER_SUBMIT'); ?>">
|
|
<span class="fa-solid fa-magnifying-glass" aria-hidden="true"></span>
|
|
</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php if ($this->countModules('menu', true)) : ?>
|
|
<nav role="navigation" aria-label="Primary">
|
|
<jdoc:include type="modules" name="menu" style="none" />
|
|
</nav>
|
|
<?php endif; ?>
|
|
<?php if ($this->countModules('search', true)) : ?>
|
|
<div class="container-search collapse" id="headerSearchCollapse">
|
|
<jdoc:include type="modules" name="search" style="none" />
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</header>
|
|
|
|
<div class="site-grid">
|
|
<?php if ($this->countModules('banner', true)) : ?>
|
|
<div class="container-banner full-width">
|
|
<jdoc:include type="modules" name="banner" style="none" />
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($this->countModules('top-a', true)) : ?>
|
|
<div class="grid-child container-top-a">
|
|
<jdoc:include type="modules" name="top-a" style="card" />
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($this->countModules('top-b', true)) : ?>
|
|
<div class="grid-child container-top-b">
|
|
<jdoc:include type="modules" name="top-b" style="card" />
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($this->countModules('sidebar-left', true)) : ?>
|
|
<div class="grid-child container-sidebar-left">
|
|
<jdoc:include type="modules" name="sidebar-left" style="card" />
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="grid-child container-component">
|
|
<jdoc:include type="modules" name="breadcrumbs" style="none" />
|
|
<?php if ($this->countModules('main-top', true)) : ?>
|
|
<div class="container-main-top">
|
|
<jdoc:include type="modules" name="main-top" style="card" />
|
|
</div>
|
|
<?php endif; ?>
|
|
<jdoc:include type="message" />
|
|
<main id="maincontent" role="main">
|
|
<jdoc:include type="component" />
|
|
</main>
|
|
<?php if ($this->countModules('main-bottom', true)) : ?>
|
|
<div class="container-main-bottom">
|
|
<jdoc:include type="modules" name="main-bottom" style="card" />
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<?php if ($this->countModules('sidebar-right', true)) : ?>
|
|
<div class="grid-child container-sidebar-right">
|
|
<jdoc:include type="modules" name="sidebar-right" style="card" />
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($this->countModules('bottom-a', true)) : ?>
|
|
<div class="grid-child container-bottom-a">
|
|
<jdoc:include type="modules" name="bottom-a" style="card" />
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($this->countModules('bottom-b', true)) : ?>
|
|
<div class="grid-child container-bottom-b">
|
|
<jdoc:include type="modules" name="bottom-b" style="card" />
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<footer class="container-footer footer full-width">
|
|
<?php if ($this->countModules('footer-menu', true)) : ?>
|
|
<div class="grid-child footer-menu">
|
|
<jdoc:include type="modules" name="footer-menu" />
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php if ($this->countModules('footer', true)) : ?>
|
|
<div class="grid-child">
|
|
<jdoc:include type="modules" name="footer" style="none" />
|
|
</div>
|
|
<?php endif; ?>
|
|
</footer>
|
|
|
|
<?php if ($this->params->get('backTop') == 1) : ?>
|
|
<a href="#top" id="back-top" class="back-to-top-link" aria-label="<?php echo Text::_('TPL_MOKOONYX_BACKTOTOP'); ?>">
|
|
<span class="fa-solid fa-arrow-up" aria-hidden="true"></span>
|
|
</a>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($this->countModules('drawer-left', true)) : ?>
|
|
<!-- Left Offcanvas Drawer -->
|
|
<aside class="offcanvas offcanvas-start" tabindex="-1" id="drawer-left">
|
|
<div class="offcanvas-header justify-content-end">
|
|
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="<?php echo Text::_('JLIB_HTML_BEHAVIOR_CLOSE'); ?>"><span class="fa fa-close"></span></button>
|
|
</div>
|
|
<div class="offcanvas-body">
|
|
<jdoc:include type="modules" name="drawer-left" style="none" />
|
|
</div>
|
|
</aside>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($this->countModules('drawer-right', true)) : ?>
|
|
<!-- Right Offcanvas Drawer -->
|
|
<aside class="offcanvas offcanvas-end" tabindex="-1" id="drawer-right">
|
|
<div class="offcanvas-header justify-content-start">
|
|
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="<?php echo Text::_('JLIB_HTML_BEHAVIOR_CLOSE'); ?>"><span class="fa fa-close"></span></button>
|
|
</div>
|
|
<div class="offcanvas-body">
|
|
<jdoc:include type="modules" name="drawer-right" style="none" />
|
|
</div>
|
|
</aside>
|
|
<?php endif; ?>
|
|
|
|
<jdoc:include type="modules" name="debug" style="none" />
|
|
|
|
</body>
|
|
</html>
|