abbd70b7f0
Universal: Auto Version Bump / Version Bump (push) Successful in 8s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Secret Scan (pull_request) Successful in 4s
Universal: PR Check / Validate PR (pull_request) Failing after 3s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Failing after 8s
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Adds two template params for the floating social icons sidebar: - social_floating_collapsible: show/hide the collapse toggle handle - social_floating_collapsed: start collapsed on first visit (default on) The layout renders the initial collapsed state server-side (no flash), gates the toggle button behind the collapsible param, and exposes the admin default via data-default-collapsed. The JS honors a visitor's saved localStorage preference first, falling back to the admin default.
136 lines
6.4 KiB
PHP
136 lines
6.4 KiB
PHP
<?php
|
|
/* Copyright (C) 2026 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;
|
|
|
|
use Joomla\CMS\Language\Text;
|
|
|
|
/**
|
|
* Social icons layout — rendered by index.php in topbar and/or footer.
|
|
*
|
|
* Expected $displayData keys:
|
|
* 'params' => Joomla\Registry\Registry (template params)
|
|
* 'position' => string ('topbar' | 'footer' | 'floating')
|
|
*/
|
|
|
|
$params = $displayData['params'];
|
|
$position = $displayData['position'] ?? 'footer';
|
|
|
|
// Platform definitions: key => [FA icon class, language key for aria-label]
|
|
$platforms = [
|
|
'facebook' => ['fa-brands fa-facebook-f', 'TPL_MOKOONYX_SOCIAL_FACEBOOK'],
|
|
'twitter' => ['fa-brands fa-x-twitter', 'TPL_MOKOONYX_SOCIAL_TWITTER'],
|
|
'instagram' => ['fa-brands fa-instagram', 'TPL_MOKOONYX_SOCIAL_INSTAGRAM'],
|
|
'linkedin' => ['fa-brands fa-linkedin-in', 'TPL_MOKOONYX_SOCIAL_LINKEDIN'],
|
|
'youtube' => ['fa-brands fa-youtube', 'TPL_MOKOONYX_SOCIAL_YOUTUBE'],
|
|
'github' => ['fa-brands fa-github', 'TPL_MOKOONYX_SOCIAL_GITHUB'],
|
|
'bluesky' => ['fa-brands fa-bluesky', 'TPL_MOKOONYX_SOCIAL_BLUESKY'],
|
|
'threads' => ['fa-brands fa-threads', 'TPL_MOKOONYX_SOCIAL_THREADS'],
|
|
'discord' => ['fa-brands fa-discord', 'TPL_MOKOONYX_SOCIAL_DISCORD'],
|
|
'tiktok' => ['fa-brands fa-tiktok', 'TPL_MOKOONYX_SOCIAL_TIKTOK'],
|
|
'reddit' => ['fa-brands fa-reddit-alien', 'TPL_MOKOONYX_SOCIAL_REDDIT'],
|
|
'pinterest' => ['fa-brands fa-pinterest-p', 'TPL_MOKOONYX_SOCIAL_PINTEREST'],
|
|
'snapchat' => ['fa-brands fa-snapchat', 'TPL_MOKOONYX_SOCIAL_SNAPCHAT'],
|
|
'telegram' => ['fa-brands fa-telegram', 'TPL_MOKOONYX_SOCIAL_TELEGRAM'],
|
|
'whatsapp' => ['fa-brands fa-whatsapp', 'TPL_MOKOONYX_SOCIAL_WHATSAPP'],
|
|
'tumblr' => ['fa-brands fa-tumblr', 'TPL_MOKOONYX_SOCIAL_TUMBLR'],
|
|
'twitch' => ['fa-brands fa-twitch', 'TPL_MOKOONYX_SOCIAL_TWITCH'],
|
|
'spotify' => ['fa-brands fa-spotify', 'TPL_MOKOONYX_SOCIAL_SPOTIFY'],
|
|
'soundcloud' => ['fa-brands fa-soundcloud', 'TPL_MOKOONYX_SOCIAL_SOUNDCLOUD'],
|
|
'flickr' => ['fa-brands fa-flickr', 'TPL_MOKOONYX_SOCIAL_FLICKR'],
|
|
'vimeo' => ['fa-brands fa-vimeo-v', 'TPL_MOKOONYX_SOCIAL_VIMEO'],
|
|
'linktree' => ['fa-solid fa-link', 'TPL_MOKOONYX_SOCIAL_LINKTREE'],
|
|
'mail' => ['fa-solid fa-envelope', 'TPL_MOKOONYX_SOCIAL_MAIL'],
|
|
];
|
|
|
|
// Collect enabled platforms (those with a non-empty URL)
|
|
$active = [];
|
|
foreach ($platforms as $key => [$iconClass, $langKey]) {
|
|
$url = trim((string) $params->get('social_' . $key . '_url', ''));
|
|
if ($url === '') {
|
|
continue;
|
|
}
|
|
if (!preg_match('#^(https?://[^\s<>"]+|mailto:[^\s<>"]+|/[^\s<>"]*)$#i', $url)) {
|
|
\Joomla\CMS\Log\Log::add(
|
|
'MokoOnyx social: skipped invalid URL for "' . $key . '": ' . $url,
|
|
\Joomla\CMS\Log\Log::WARNING,
|
|
'template'
|
|
);
|
|
continue;
|
|
}
|
|
$active[] = [
|
|
'url' => $url,
|
|
'iconClass' => $iconClass,
|
|
'label' => Text::_($langKey),
|
|
];
|
|
}
|
|
|
|
if (empty($active)) {
|
|
return;
|
|
}
|
|
|
|
$style = in_array($params->get('social_icon_style'), ['plain', 'square', 'circle', 'rounded'], true)
|
|
? $params->get('social_icon_style') : 'plain';
|
|
$size = in_array($params->get('social_icon_size'), ['sm', 'md', 'lg'], true)
|
|
? $params->get('social_icon_size') : 'md';
|
|
|
|
$floatingPos = in_array($params->get('social_floating_pos'), ['left', 'right'], true)
|
|
? $params->get('social_floating_pos') : 'left';
|
|
$colorMode = in_array($params->get('social_icon_color'), ['theme', 'brand', 'black', 'white'], true)
|
|
? $params->get('social_icon_color') : 'theme';
|
|
|
|
// Floating collapse behaviour (only meaningful for the floating position)
|
|
$collapsible = (bool) $params->get('social_floating_collapsible', 1);
|
|
$collapsedDefault = $collapsible && (bool) $params->get('social_floating_collapsed', 1);
|
|
|
|
$listClass = 'moko-social-icons';
|
|
$listClass .= ' moko-social-icons--' . htmlspecialchars($style, ENT_QUOTES, 'UTF-8');
|
|
$listClass .= ' moko-social-icons--' . htmlspecialchars($size, ENT_QUOTES, 'UTF-8');
|
|
$listClass .= ' moko-social-icons--' . htmlspecialchars($position, ENT_QUOTES, 'UTF-8');
|
|
$listClass .= ' moko-social-icons--color-' . $colorMode;
|
|
if ($position === 'floating') {
|
|
$listClass .= ' moko-social-icons--floating-' . $floatingPos;
|
|
}
|
|
?>
|
|
<?php if ($position === 'floating') : ?>
|
|
<div class="moko-social-floating-wrap moko-social-floating-wrap--<?php echo htmlspecialchars($floatingPos, ENT_QUOTES, 'UTF-8'); ?><?php echo $collapsedDefault ? ' is-collapsed' : ''; ?>"
|
|
id="mokoSocialFloating"
|
|
data-collapsible="<?php echo $collapsible ? '1' : '0'; ?>"
|
|
data-default-collapsed="<?php echo $collapsedDefault ? '1' : '0'; ?>">
|
|
<?php endif; ?>
|
|
<nav class="<?php echo $listClass; ?>" aria-label="<?php echo Text::_('TPL_MOKOONYX_SOCIAL_NAV_LABEL'); ?>">
|
|
<ul>
|
|
<?php foreach ($active as $item) : ?>
|
|
<li>
|
|
<a href="<?php echo htmlspecialchars($item['url'], ENT_QUOTES, 'UTF-8'); ?>"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
aria-label="<?php echo htmlspecialchars($item['label'], ENT_QUOTES, 'UTF-8'); ?>"
|
|
data-bs-toggle="tooltip"
|
|
data-bs-placement="<?php echo $position === 'floating' ? ($floatingPos === 'left' ? 'right' : 'left') : 'top'; ?>"
|
|
title="<?php echo htmlspecialchars($item['label'], ENT_QUOTES, 'UTF-8'); ?>">
|
|
<span class="<?php echo htmlspecialchars($item['iconClass'], ENT_QUOTES, 'UTF-8'); ?>" aria-hidden="true"></span>
|
|
</a>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
</nav>
|
|
<?php if ($position === 'floating' && $collapsible) : ?>
|
|
<button type="button"
|
|
class="moko-social-floating-toggle"
|
|
id="mokoSocialFloatingToggle"
|
|
aria-controls="mokoSocialFloating"
|
|
aria-label="<?php echo Text::_('TPL_MOKOONYX_SOCIAL_FLOATING_TOGGLE'); ?>"
|
|
aria-expanded="<?php echo $collapsedDefault ? 'false' : 'true'; ?>">
|
|
<span class="fa-solid fa-chevron-<?php echo $floatingPos === 'left' ? 'left' : 'right'; ?>" aria-hidden="true"></span>
|
|
</button>
|
|
<?php endif; ?>
|
|
<?php if ($position === 'floating') : ?>
|
|
</div>
|
|
<?php endif; ?>
|