feat: card fade-in delay and video mute toggle #41

Merged
jmiller merged 5 commits from dev into main 2026-05-30 19:08:41 +00:00
10 changed files with 248 additions and 15 deletions
+30 -8
View File
@@ -52,22 +52,22 @@ jobs:
REASON="Fix branches must target 'dev', not '${BASE}'"
fi
;;
patch/*)
if [ "$BASE" != "dev" ] && [ "$BASE" != "rc" ]; then
ALLOWED=false
REASON="Patch branches must target 'dev' or 'rc', not '${BASE}'"
fi
;;
hotfix/*)
if [ "$BASE" != "dev" ] && [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Hotfix branches can only target 'dev' or 'main', not '${BASE}'"
fi
;;
alpha/*|beta/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Pre-release branches must target 'dev', not '${BASE}'"
fi
;;
rc/*)
rc)
if [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Release candidate branches must target 'main', not '${BASE}'"
REASON="RC branch can only merge into 'main', not '${BASE}'"
fi
;;
dev)
@@ -183,6 +183,28 @@ jobs:
;;
esac
- name: Check changelog has unreleased entry
run: |
if [ ! -f "CHANGELOG.md" ]; then
echo "::warning::No CHANGELOG.md found"
exit 0
fi
# Check for content under [Unreleased] section
if ! grep -q "## \[Unreleased\]" CHANGELOG.md; then
echo "::error::CHANGELOG.md missing [Unreleased] section"
exit 1
fi
# Check there's at least one entry (Added/Changed/Fixed/Removed) under Unreleased
UNRELEASED_CONTENT=$(sed -n '/## \[Unreleased\]/,/## \[/p' CHANGELOG.md | grep -cE '^\s*-\s' || true)
if [ "$UNRELEASED_CONTENT" -eq 0 ]; then
echo "::error::CHANGELOG.md [Unreleased] section has no entries. Add a changelog entry describing your changes."
echo "## Changelog Check: Failed" >> $GITHUB_STEP_SUMMARY
echo "The \`[Unreleased]\` section in CHANGELOG.md has no entries." >> $GITHUB_STEP_SUMMARY
echo "Add a line like \`- Description of your change\` under a heading (\`### Added\`, \`### Changed\`, \`### Fixed\`, etc.)" >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "Changelog: ${UNRELEASED_CONTENT} entry/entries in [Unreleased]"
- name: Verify package source
run: |
SOURCE_DIR="src"
+17
View File
@@ -7,6 +7,23 @@ Version format: `XX.YY.ZZ` (zero-padded semver).
## [Unreleased]
### Planned
- Configurable card fade-in delay (#39)
- Video audio mute/unmute option (#40)
## [01.01.00] - 2026-05-30
### Fixed
- WebAsset registration: added `#style`/`#script` suffixes to preset dependencies (was causing `UnsatisfiedDependencyException`)
- Asset URI resolution: use `extension/filename` pattern instead of `extension/folder/filename` (Joomla auto-inserts `css/`/`js/` folders)
- iframe video cover: split CSS into `<video>` (`object-fit: cover`) and `<iframe>` (oversize + centre-crop) rules since `object-fit` doesn't apply to iframes
- Card link styling: exclude `.btn` elements from `color: inherit` so buttons retain their own styles
### Added
- Module title renders inside the hero card as `<h2>`, respecting Joomla's Show Title toggle
- IntersectionObserver pauses/resumes videos when the hero scrolls out of/into the viewport (YouTube, Vimeo, and native `<video>`)
- YouTube embeds include `enablejsapi=1` for postMessage playback control
### Changed
- Migrated all workflow and template paths from `.github/` to `.mokogitea/`
- Template source paths updated
+8
View File
@@ -36,6 +36,14 @@ MOD_MOKOJOOMHERO_SLIDE_INTERVAL_DESC="Time between slides in milliseconds (e.g.
MOD_MOKOJOOMHERO_VIDEO_FILE_LABEL="Video URL"
MOD_MOKOJOOMHERO_VIDEO_FILE_DESC="Local file path, YouTube URL, or Vimeo URL. Any format works — the module auto-detects the source."
; Card delay
MOD_MOKOJOOMHERO_CARD_DELAY_LABEL="Card Fade-in Delay (ms)"
MOD_MOKOJOOMHERO_CARD_DELAY_DESC="Delay in milliseconds before the content card fades in. Set to 0 for no delay."
; Mute toggle
MOD_MOKOJOOMHERO_MUTE_TOGGLE_LABEL="Show Mute Toggle"
MOD_MOKOJOOMHERO_MUTE_TOGGLE_DESC="Show a mute/unmute button on the hero video. Videos always start muted (required for autoplay)."
; Hero height
MOD_MOKOJOOMHERO_HERO_HEIGHT_LABEL="Hero Height"
MOD_MOKOJOOMHERO_HERO_HEIGHT_DESC="Height of the hero section. Use px for fixed pixels (e.g. 400px) or vh for viewport height (e.g. 60vh for 60%% of screen)."
+8
View File
@@ -41,6 +41,14 @@ MOD_MOKOJOOMHERO_HERO_HEIGHT_LABEL="Hero Height"
MOD_MOKOJOOMHERO_HERO_HEIGHT_DESC="Height of the hero section. Use px for fixed pixels (e.g. 400px) or vh for viewport height (e.g. 60vh for 60% of screen)."
MOD_MOKOJOOMHERO_HERO_HEIGHT_HINT="e.g. 60vh or 400px"
; Card delay
MOD_MOKOJOOMHERO_CARD_DELAY_LABEL="Card Fade-in Delay (ms)"
MOD_MOKOJOOMHERO_CARD_DELAY_DESC="Delay in milliseconds before the content card fades in. Set to 0 for no delay."
; Mute toggle
MOD_MOKOJOOMHERO_MUTE_TOGGLE_LABEL="Show Mute Toggle"
MOD_MOKOJOOMHERO_MUTE_TOGGLE_DESC="Show a mute/unmute button on the hero video. Videos always start muted (required for autoplay)."
; Overlay fieldset
MOD_MOKOJOOMHERO_FIELDSET_OVERLAY="Overlay &amp; Text"
MOD_MOKOJOOMHERO_OVERLAY_COLOR_LABEL="Overlay Color"
+39
View File
@@ -126,6 +126,45 @@ iframe.mokojoomhero__video {
text-decoration: underline;
}
/* ============================================================
Card fade-in delay
============================================================ */
.mokojoomhero__card[data-card-delay] {
opacity: 0;
animation: mokojoomhero-fadein 0.6s ease forwards;
}
@keyframes mokojoomhero-fadein {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
/* ============================================================
Mute toggle
============================================================ */
.mokojoomhero__mute-toggle {
position: absolute;
bottom: 1rem;
right: 1rem;
z-index: 2;
background: rgba(0, 0, 0, 0.5);
color: #fff;
border: none;
border-radius: 50%;
width: 40px;
height: 40px;
font-size: 1.2rem;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s;
}
.mokojoomhero__mute-toggle:hover {
background: rgba(0, 0, 0, 0.7);
}
/* ============================================================
Responsive
============================================================ */
+30
View File
@@ -85,4 +85,34 @@ document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('.mokojoomhero').forEach(function (hero) {
observer.observe(hero);
});
// ── Mute/unmute toggle ──
document.querySelectorAll('.mokojoomhero__mute-toggle').forEach(function (btn) {
var hero = btn.closest('.mokojoomhero');
var video = hero.querySelector('video.mokojoomhero__video');
var iframe = hero.querySelector('iframe.mokojoomhero__video');
var icon = btn.querySelector('.mokojoomhero__mute-icon');
btn.addEventListener('click', function () {
var muted = btn.getAttribute('data-muted') === 'true';
if (video) {
video.muted = !muted;
}
if (iframe) {
var src = iframe.src || '';
if (src.indexOf('youtube') !== -1) {
var func = muted ? 'unMute' : 'mute';
iframe.contentWindow.postMessage('{"event":"command","func":"' + func + '","args":""}', '*');
} else if (src.indexOf('vimeo') !== -1) {
var vol = muted ? 1 : 0;
iframe.contentWindow.postMessage('{"method":"setVolume","value":' + vol + '}', '*');
}
}
btn.setAttribute('data-muted', muted ? 'false' : 'true');
btn.setAttribute('aria-label', muted ? 'Mute video' : 'Unmute video');
icon.textContent = muted ? '\u{1F50A}' : '\u{1F507}';
});
});
});
+2
View File
@@ -35,6 +35,8 @@ $textAlign = $params->get('textAlign', 'center');
$textColor = $params->get('textColor', '#ffffff');
$heroContent = $params->get('heroContent', '');
$showCard = (bool) $params->get('showCard', 1);
$cardDelay = (int) $params->get('cardDelay', 0);
$showMuteToggle = (bool) $params->get('showMuteToggle', 0);
// Collect hero images
$heroImages = [];
+23
View File
@@ -104,6 +104,18 @@
default="60vh"
filter="string"
/>
<field
name="showMuteToggle"
type="radio"
layout="joomla.form.field.radio.switcher"
label="MOD_MOKOJOOMHERO_MUTE_TOGGLE_LABEL"
description="MOD_MOKOJOOMHERO_MUTE_TOGGLE_DESC"
default="0"
showon="heroMode:video"
>
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
</fieldset>
<fieldset name="content"
label="MOD_MOKOJOOMHERO_FIELDSET_CONTENT"
@@ -128,6 +140,17 @@
<option value="0">JNO</option>
<option value="1">JYES</option>
</field>
<field
name="cardDelay"
type="number"
label="MOD_MOKOJOOMHERO_CARD_DELAY_LABEL"
description="MOD_MOKOJOOMHERO_CARD_DELAY_DESC"
default="0"
min="0"
max="5000"
step="250"
showon="showCard:1"
/>
</fieldset>
<fieldset name="advanced"
label="MOD_MOKOJOOMHERO_FIELDSET_OVERLAY"
+9 -1
View File
@@ -25,6 +25,8 @@ use Joomla\CMS\Language\Text;
/** @var string $textColor */
/** @var string $heroContent */
/** @var bool $showCard */
/** @var int $cardDelay */
/** @var bool $showMuteToggle */
/** @var string $content */
$moduleId = 'mod-mokojoomhero-' . $module->id;
@@ -61,12 +63,18 @@ $heightAttr = htmlspecialchars($heroHeight, ENT_QUOTES, 'UTF-8');
<?php endforeach; ?>
<?php endif; ?>
<?php if ($heroMode === 'video' && $showMuteToggle) : ?>
<button class="mokojoomhero__mute-toggle" type="button" aria-label="Unmute video" data-muted="true">
<span class="mokojoomhero__mute-icon" aria-hidden="true">&#x1F507;</span>
</button>
<?php endif; ?>
<?php // Overlay + content ?>
<div class="mokojoomhero__overlay" style="background-color: <?php echo $rgba; ?>;">
<div class="mokojoomhero__content" style="text-align: <?php echo htmlspecialchars($textAlign, ENT_QUOTES, 'UTF-8'); ?>; color: <?php echo htmlspecialchars($textColor, ENT_QUOTES, 'UTF-8'); ?>;">
<?php if ($heroContent || $module->showtitle) : ?>
<?php if ($showCard) : ?>
<div class="mokojoomhero__card">
<div class="mokojoomhero__card"<?php if ($cardDelay) : ?> style="animation-delay: <?php echo $cardDelay; ?>ms;" data-card-delay="<?php echo $cardDelay; ?>"<?php endif; ?>>
<?php if ($module->showtitle) : ?>
<h2 class="mokojoomhero__title"><?php echo htmlspecialchars($module->title, ENT_QUOTES, 'UTF-8'); ?></h2>
<?php endif; ?>
+82 -6
View File
@@ -1,27 +1,103 @@
<?xml version='1.0' encoding='UTF-8'?>
<!-- Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
SPDX-License-Identifier: GPL-3.0-or-later
VERSION: 01.00.20
VERSION: 01.01.00
-->
<updates>
<update>
<name>Module - MokoJoomHero</name>
<description>Module - MokoJoomHero development build.</description>
<description>Module - MokoJoomHero dev build.</description>
<element>mod_mokojoomhero</element>
<type>module</type>
<client>site</client>
<version>01.00.18-dev</version>
<version>01.01.00-dev</version>
<creationDate>2026-05-30</creationDate>
<infourl title='Module - MokoJoomHero'>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/tag/development</infourl>
<infourl title="Module - MokoJoomHero">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/tag/development</infourl>
<downloads>
<downloadurl type='full' format='zip'>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/development/mod_mokojoomhero-01.00.18-dev.zip</downloadurl>
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/development/mod_mokojoomhero-01.01.00-dev.zip</downloadurl>
</downloads>
<sha256>a629c54e31bcb6761d709a1b3c384c788172694365922dfad1b737fe502cf6c2</sha256>
<sha256>f07dbfd79e507c3fb250cc34618940ef226bf58053b96b8d893cd9d33237717e</sha256>
<tags><tag>dev</tag></tags>
<changelogurl>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/main/CHANGELOG.md</changelogurl>
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
<targetplatform name="joomla" version="(5|6)\..*"/>
</update>
<update>
<name>Module - MokoJoomHero</name>
<description>Module - MokoJoomHero alpha build.</description>
<element>mod_mokojoomhero</element>
<type>module</type>
<client>site</client>
<version>01.01.00-alpha</version>
<creationDate>2026-05-30</creationDate>
<infourl title="Module - MokoJoomHero">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/tag/alpha</infourl>
<downloads>
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/alpha/mod_mokojoomhero-01.01.00-alpha.zip</downloadurl>
</downloads>
<sha256>f07dbfd79e507c3fb250cc34618940ef226bf58053b96b8d893cd9d33237717e</sha256>
<tags><tag>alpha</tag></tags>
<changelogurl>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/main/CHANGELOG.md</changelogurl>
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
<targetplatform name="joomla" version="(5|6)\..*"/>
</update>
<update>
<name>Module - MokoJoomHero</name>
<description>Module - MokoJoomHero beta build.</description>
<element>mod_mokojoomhero</element>
<type>module</type>
<client>site</client>
<version>01.01.00-beta</version>
<creationDate>2026-05-30</creationDate>
<infourl title="Module - MokoJoomHero">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/tag/beta</infourl>
<downloads>
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/beta/mod_mokojoomhero-01.01.00-beta.zip</downloadurl>
</downloads>
<sha256>f07dbfd79e507c3fb250cc34618940ef226bf58053b96b8d893cd9d33237717e</sha256>
<tags><tag>beta</tag></tags>
<changelogurl>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/main/CHANGELOG.md</changelogurl>
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
<targetplatform name="joomla" version="(5|6)\..*"/>
</update>
<update>
<name>Module - MokoJoomHero</name>
<description>Module - MokoJoomHero rc build.</description>
<element>mod_mokojoomhero</element>
<type>module</type>
<client>site</client>
<version>01.01.00-rc</version>
<creationDate>2026-05-30</creationDate>
<infourl title="Module - MokoJoomHero">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/tag/release-candidate</infourl>
<downloads>
<downloadurl type="full" format="zip">https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/release-candidate/mod_mokojoomhero-01.01.00-rc.zip</downloadurl>
</downloads>
<sha256>f07dbfd79e507c3fb250cc34618940ef226bf58053b96b8d893cd9d33237717e</sha256>
<tags><tag>rc</tag></tags>
<changelogurl>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/main/CHANGELOG.md</changelogurl>
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
<targetplatform name="joomla" version="(5|6)\..*"/>
</update>
<update>
<name>Module - MokoJoomHero</name>
<description>Module - MokoJoomHero stable build.</description>
<element>mod_mokojoomhero</element>
<type>module</type>
<client>site</client>
<version>01.01.00</version>
<creationDate>2026-05-30</creationDate>
<infourl title='Module - MokoJoomHero'>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/tag/stable</infourl>
<downloads>
<downloadurl type='full' format='zip'>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/stable/mod_mokojoomhero-01.01.00.zip</downloadurl>
</downloads>
<sha256>f07dbfd79e507c3fb250cc34618940ef226bf58053b96b8d893cd9d33237717e</sha256>
<tags><tag>stable</tag></tags>
<changelogurl>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/main/CHANGELOG.md</changelogurl>
<maintainer>Moko Consulting</maintainer>
<maintainerurl>https://mokoconsulting.tech</maintainerurl>
<targetplatform name="joomla" version="(5|6)\..*" />
</update>
</updates>