Release: WebAsset fixes, hero card title, video viewport pause #38
@@ -202,3 +202,8 @@ hypothesis/
|
||||
|
||||
profile.ps1
|
||||
.mcp.json
|
||||
|
||||
# ============================================================
|
||||
# Wiki (managed separately via Gitea wiki)
|
||||
# ============================================================
|
||||
wiki/
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<name>MokoJoomHero</name>
|
||||
<org>MokoConsulting</org>
|
||||
<description>A Joomla Module designed to provide a random image from a folder with content on top as a Hero.</description>
|
||||
<version>01.00.20</version>
|
||||
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
|
||||
</identity>
|
||||
<governance>
|
||||
@@ -20,6 +21,8 @@
|
||||
<build>
|
||||
<language>PHP</language>
|
||||
<package-type>joomla</package-type>
|
||||
<joomla-type>module</joomla-type>
|
||||
<joomla-element>mod_mokojoomhero</joomla-element>
|
||||
<entry-point>src/</entry-point>
|
||||
</build>
|
||||
</moko-platform>
|
||||
|
||||
@@ -52,7 +52,7 @@ jobs:
|
||||
- name: Discover target branches
|
||||
id: branches
|
||||
env:
|
||||
GA_TOKEN: ${{ secrets.GA_TOKEN }}
|
||||
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||
run: |
|
||||
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
ALL_BRANCHES=""
|
||||
while true; do
|
||||
BATCH=$(curl -sS \
|
||||
-H "Authorization: token ${GA_TOKEN}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${API}/branches?page=${PAGE}&limit=50" \
|
||||
| jq -r '.[].name // empty')
|
||||
[ -z "$BATCH" ] && break
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
- name: Cascade to all target branches
|
||||
if: steps.branches.outputs.targets != ''
|
||||
env:
|
||||
GA_TOKEN: ${{ secrets.GA_TOKEN }}
|
||||
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||
run: |
|
||||
API="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
|
||||
SHORT_SHA="${GITHUB_SHA:0:7}"
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
# Check if branch is already up to date
|
||||
ENCODED_BRANCH=$(echo "$BRANCH" | sed 's|/|%2F|g')
|
||||
RESPONSE=$(curl -sS \
|
||||
-H "Authorization: token ${GA_TOKEN}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${API}/compare/${ENCODED_BRANCH}...main")
|
||||
|
||||
AHEAD=$(echo "$RESPONSE" | jq '.total_commits // 0')
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
|
||||
# Check for existing cascade PR
|
||||
EXISTING=$(curl -sS \
|
||||
-H "Authorization: token ${GA_TOKEN}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${API}/pulls?state=open&head=${GITEA_ORG}:main&base=${ENCODED_BRANCH}&limit=1")
|
||||
|
||||
EXISTING_COUNT=$(echo "$EXISTING" | jq 'length')
|
||||
@@ -139,7 +139,7 @@ jobs:
|
||||
# Create cascade PR
|
||||
PR_RESPONSE=$(curl -sS -w "\n%{http_code}" \
|
||||
-X POST \
|
||||
-H "Authorization: token ${GA_TOKEN}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"title\": \"chore: cascade main → ${BRANCH} (${SHORT_SHA}) [skip ci]\",
|
||||
@@ -165,7 +165,7 @@ jobs:
|
||||
|
||||
# Try auto-merge
|
||||
PR_DATA=$(curl -sS \
|
||||
-H "Authorization: token ${GA_TOKEN}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${API}/pulls/${PR_NUMBER}")
|
||||
|
||||
MERGEABLE=$(echo "$PR_DATA" | jq -r '.mergeable // false')
|
||||
@@ -178,7 +178,7 @@ jobs:
|
||||
|
||||
MERGE_RESPONSE=$(curl -sS -w "\n%{http_code}" \
|
||||
-X POST \
|
||||
-H "Authorization: token ${GA_TOKEN}" \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"Do\": \"merge\",
|
||||
|
||||
@@ -43,9 +43,9 @@ jobs:
|
||||
|
||||
- name: Clone MokoStandards
|
||||
env:
|
||||
GA_TOKEN: ${{ secrets.GA_TOKEN || secrets.GA_TOKEN || github.token }}
|
||||
MOKO_CLONE_TOKEN: ${{ secrets.GA_TOKEN || secrets.GA_TOKEN || github.token }}
|
||||
MOKO_CLONE_HOST: ${{ secrets.GA_TOKEN && 'git.mokoconsulting.tech/MokoConsulting' || 'github.com/mokoconsulting-tech' }}
|
||||
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN || secrets.MOKOGITEA_TOKEN || github.token }}
|
||||
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN || secrets.MOKOGITEA_TOKEN || github.token }}
|
||||
MOKO_CLONE_HOST: ${{ secrets.MOKOGITEA_TOKEN && 'git.mokoconsulting.tech/MokoConsulting' || 'github.com/mokoconsulting-tech' }}
|
||||
run: |
|
||||
git clone --depth 1 --branch main --quiet \
|
||||
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/MokoStandards-API.git" \
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
env:
|
||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GA_TOKEN || github.token }}"}}'
|
||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.MOKOGITEA_TOKEN || github.token }}"}}'
|
||||
run: |
|
||||
if [ -f "composer.json" ]; then
|
||||
composer install \
|
||||
@@ -346,7 +346,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
env:
|
||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GA_TOKEN || github.token }}"}}'
|
||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.MOKOGITEA_TOKEN || github.token }}"}}'
|
||||
run: |
|
||||
if [ -f "composer.json" ]; then
|
||||
composer install \
|
||||
@@ -391,7 +391,7 @@ jobs:
|
||||
|
||||
- name: Install dependencies
|
||||
env:
|
||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GA_TOKEN || github.token }}"}}'
|
||||
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.MOKOGITEA_TOKEN || github.token }}"}}'
|
||||
run: |
|
||||
if [ -f "composer.json" ]; then
|
||||
composer install --no-interaction --prefer-dist --optimize-autoloader
|
||||
@@ -458,10 +458,10 @@ jobs:
|
||||
steps:
|
||||
- name: Trigger pre-release build
|
||||
env:
|
||||
GA_TOKEN: ${{ secrets.GA_TOKEN }}
|
||||
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||
REPO: ${{ github.repository }}
|
||||
BRANCH: ${{ github.head_ref }}
|
||||
run: |
|
||||
curl -s -X POST "${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${GA_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}"
|
||||
curl -s -X POST "${GITEA_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}"
|
||||
echo "### Pre-Release" >> $GITHUB_STEP_SUMMARY
|
||||
echo "Triggered RC build on branch \`${BRANCH}\`" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
@@ -33,17 +33,17 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.GA_TOKEN }}
|
||||
token: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||
|
||||
- name: Delete merged branches
|
||||
env:
|
||||
GA_TOKEN: ${{ secrets.GA_TOKEN }}
|
||||
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||
run: |
|
||||
echo "=== Merged Branch Cleanup ==="
|
||||
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
|
||||
|
||||
# List branches via API
|
||||
BRANCHES=$(curl -sS -H "Authorization: token ${GA_TOKEN}" \
|
||||
BRANCHES=$(curl -sS -H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${API}/branches?limit=50" | jq -r '.[].name')
|
||||
|
||||
DELETED=0
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
# Check if branch is merged into main
|
||||
if git merge-base --is-ancestor "origin/${BRANCH}" origin/main 2>/dev/null; then
|
||||
echo " Deleting merged branch: ${BRANCH}"
|
||||
curl -sS -X DELETE -H "Authorization: token ${GA_TOKEN}" \
|
||||
curl -sS -X DELETE -H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${API}/branches/${BRANCH}" 2>/dev/null || true
|
||||
DELETED=$((DELETED + 1))
|
||||
fi
|
||||
@@ -66,20 +66,20 @@ jobs:
|
||||
|
||||
- name: Clean old workflow runs
|
||||
env:
|
||||
GA_TOKEN: ${{ secrets.GA_TOKEN }}
|
||||
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||
run: |
|
||||
echo "=== Workflow Run Cleanup ==="
|
||||
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
|
||||
CUTOFF=$(date -d "30 days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -v-30d +%Y-%m-%dT%H:%M:%SZ)
|
||||
|
||||
# Get old completed runs
|
||||
RUNS=$(curl -sS -H "Authorization: token ${GA_TOKEN}" \
|
||||
RUNS=$(curl -sS -H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${API}/actions/runs?status=completed&limit=50" | \
|
||||
jq -r ".workflow_runs[] | select(.created_at < \"${CUTOFF}\") | .id" 2>/dev/null)
|
||||
|
||||
DELETED=0
|
||||
for RUN_ID in $RUNS; do
|
||||
curl -sS -X DELETE -H "Authorization: token ${GA_TOKEN}" \
|
||||
curl -sS -X DELETE -H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${API}/actions/runs/${RUN_ID}" 2>/dev/null || true
|
||||
DELETED=$((DELETED + 1))
|
||||
done
|
||||
|
||||
@@ -204,11 +204,11 @@ jobs:
|
||||
steps:
|
||||
- name: Trigger RC pre-release
|
||||
env:
|
||||
GA_TOKEN: ${{ secrets.GA_TOKEN }}
|
||||
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
|
||||
REPO: ${{ github.repository }}
|
||||
BRANCH: ${{ github.head_ref }}
|
||||
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
|
||||
run: |
|
||||
curl -s -X POST "${GITEA_URL}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${GA_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}"
|
||||
curl -s -X POST "${GITEA_URL}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}"
|
||||
echo "### Pre-Release" >> $GITHUB_STEP_SUMMARY
|
||||
echo "Triggered RC build on branch \`${BRANCH}\`" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
@@ -49,7 +49,7 @@ env:
|
||||
SCRIPTS_ALLOWED_DIRS: scripts,scripts/fix,scripts/lib,scripts/release,scripts/run,scripts/validate
|
||||
|
||||
# Repo health policy
|
||||
REPO_REQUIRED_ARTIFACTS: README.md,LICENSE,CHANGELOG.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,.gitea/workflows/
|
||||
REPO_REQUIRED_ARTIFACTS: README.md,LICENSE,CHANGELOG.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,.mokogitea/workflows/
|
||||
REPO_OPTIONAL_FILES: SECURITY.md,GOVERNANCE.md,.editorconfig,.gitattributes,.gitignore,README.md,docs/
|
||||
REPO_DISALLOWED_DIRS:
|
||||
REPO_DISALLOWED_FILES: TODO.md,todo.md
|
||||
@@ -60,7 +60,7 @@ env:
|
||||
# File / directory variables
|
||||
DOCS_INDEX: docs/docs-index.md
|
||||
SCRIPT_DIR: scripts
|
||||
WORKFLOWS_DIR: .gitea/workflows
|
||||
WORKFLOWS_DIR: .mokogitea/workflows
|
||||
SHELLCHECK_PATTERN: '*.sh'
|
||||
SPDX_FILE_GLOBS: '*.sh,*.php,*.js,*.ts,*.css,*.xml,*.yml,*.yaml'
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
||||
@@ -81,7 +81,7 @@ jobs:
|
||||
- name: Check actor permission (admin only)
|
||||
id: perm
|
||||
env:
|
||||
TOKEN: ${{ secrets.GA_TOKEN || secrets.GA_TOKEN || github.token }}
|
||||
TOKEN: ${{ secrets.MOKOGITEA_TOKEN || secrets.MOKOGITEA_TOKEN || github.token }}
|
||||
REPO: ${{ github.repository }}
|
||||
ACTOR: ${{ github.actor }}
|
||||
run: |
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
DEFGROUP:
|
||||
INGROUP: Project.Documentation
|
||||
REPO:
|
||||
VERSION: 04.04.01
|
||||
VERSION: 01.00.20
|
||||
PATH: ./CODE_OF_CONDUCT.md
|
||||
BRIEF: Reference + packaging repo for Moko Consulting Developer GPT Other Default
|
||||
-->
|
||||
|
||||
+108
-141
@@ -1,161 +1,128 @@
|
||||
# Contributing to Moko Consulting Projects
|
||||
<!--
|
||||
Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
|
||||
Thank you for your interest in contributing. All Moko Consulting repositories follow this universal workflow and version policy.
|
||||
This file is part of a Moko Consulting project.
|
||||
|
||||
## Branching Workflow
|
||||
SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License (./LICENSE).
|
||||
|
||||
# FILE INFORMATION
|
||||
DEFGROUP: {{DEFGROUP}}
|
||||
INGROUP: Project.Documentation
|
||||
REPO: https://github.com/mokoconsulting-tech/MokoJoomHero
|
||||
VERSION: 01.00.20
|
||||
PATH: ./CONTRIBUTING.md
|
||||
BRIEF: How to contribute; branch strategy, commit conventions, PR workflow, and release pipeline
|
||||
-->
|
||||
|
||||
# Contributing
|
||||
|
||||
Thank you for your interest in contributing to **MokoJoomHero**!
|
||||
|
||||
This repository is governed by **[MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards)** — the authoritative source of coding standards, workflows, and policies for all Moko Consulting repositories.
|
||||
|
||||
## Branch Strategy
|
||||
|
||||
| Branch | Purpose | Deploys To |
|
||||
|--------|---------|------------|
|
||||
| `main` | Bleeding edge — all development merges here | CI only |
|
||||
| `dev/XX.YY.ZZ` | Feature development | Dev server (version: "development") |
|
||||
| `version/XX.YY` | Stable frozen snapshot | Demo + RS servers |
|
||||
|
||||
### Development Workflow
|
||||
|
||||
```
|
||||
feature/* ──PR──> dev ──draft PR──> (renamed to rc) ──merge──> main
|
||||
1. Create branch: git checkout -b dev/XX.YY.ZZ/my-feature
|
||||
2. Develop + test (dev server auto-deploys on push)
|
||||
3. Open PR → main (squash merge only)
|
||||
4. Auto-release (version branch + tag + GitHub Release created automatically)
|
||||
```
|
||||
|
||||
### Step by step
|
||||
### Branch Naming
|
||||
|
||||
1. **Create a feature branch** from `dev`:
|
||||
```bash
|
||||
git checkout dev && git pull
|
||||
git checkout -b feature/my-change
|
||||
```
|
||||
| Prefix | Use |
|
||||
|--------|-----|
|
||||
| `dev/XX.YY.ZZ` | Feature development (e.g., `dev/02.00.00/add-extrafields`) |
|
||||
| `version/XX.YY` | Stable release (auto-created, never manually pushed) |
|
||||
| `chore/` | Automated sync branches (managed by MokoStandards) |
|
||||
|
||||
2. **Work and commit** on your feature branch. Push to origin.
|
||||
> **Never use** `feature/`, `hotfix/`, or `release/` prefixes — they are not part of the MokoStandards branch strategy.
|
||||
|
||||
3. **Open a PR**: `feature/my-change` → `dev`. After review and checks, merge it.
|
||||
## Commit Conventions
|
||||
|
||||
4. **When ready for release**, open a **draft PR**: `dev` → `main`.
|
||||
- This automatically renames the source branch to `rc` (release candidate)
|
||||
- An RC pre-release is built and uploaded
|
||||
|
||||
5. **Alpha and beta branches** are created by manually renaming the branch before the RC stage:
|
||||
- Rename `dev` to `alpha` for early testing → alpha pre-release is built
|
||||
- Rename `alpha` to `beta` for feature-complete testing → beta pre-release is built
|
||||
- When the draft PR is created, the branch is renamed to `rc`
|
||||
|
||||
6. **Once PR checks pass** on the `rc` branch, mark the PR as ready and merge to `main`.
|
||||
|
||||
7. **Merging to main** triggers the stable release pipeline:
|
||||
- Minor version bump (e.g., `02.09.xx` → `02.10.00`)
|
||||
- Stability suffix stripped (clean version)
|
||||
- Gitea release created with ZIP/tar.gz packages
|
||||
- `updates.xml` updated (Joomla extensions)
|
||||
- `dev` branch recreated from `main`
|
||||
|
||||
### Branch summary
|
||||
|
||||
| Branch | Purpose | Created by |
|
||||
|--------|---------|-----------|
|
||||
| `feature/*` | New features and fixes | Developer |
|
||||
| `dev` | Integration branch | Auto-recreated after release |
|
||||
| `alpha` | Alpha pre-release testing | Manual rename from `dev` |
|
||||
| `beta` | Beta pre-release testing | Manual rename from `alpha` |
|
||||
| `rc` | Release candidate | Auto-renamed on draft PR to main |
|
||||
| `main` | Stable releases | Protected, merge only |
|
||||
| `version/XX.YY.ZZ` | Archived release snapshots | Auto-created by CI |
|
||||
|
||||
### Protected branches
|
||||
|
||||
| Branch | Direct push | Merge via |
|
||||
|--------|------------|-----------|
|
||||
| `main` | Blocked (CI bot whitelisted) | PR merge only |
|
||||
| `dev` | Blocked (CI bot whitelisted) | PR merge from feature/* |
|
||||
| `rc` | Blocked (CI bot whitelisted) | Auto-created on draft PR |
|
||||
| `alpha` | Blocked (CI bot whitelisted) | Manual rename |
|
||||
| `beta` | Blocked (CI bot whitelisted) | Manual rename |
|
||||
| `feature/*` | Open | N/A (source branch) |
|
||||
|
||||
## Version Policy
|
||||
|
||||
### Format
|
||||
|
||||
All versions use `XX.YY.ZZ` — three two-digit segments, zero-padded:
|
||||
|
||||
- **XX** — Major version (breaking changes)
|
||||
- **YY** — Minor version (new features, bumped on release to main)
|
||||
- **ZZ** — Patch version (auto-incremented on every push to dev/feature branches)
|
||||
|
||||
Rollover: patch `99` → `00` increments minor; minor `99` → `00` increments major.
|
||||
|
||||
### Stability suffixes
|
||||
|
||||
Each branch appends a suffix to indicate stability:
|
||||
|
||||
| Branch | Suffix | Example |
|
||||
|--------|--------|---------|
|
||||
| `main` | (none) | `02.09.00` |
|
||||
| `dev` | `-dev` | `02.09.01-dev` |
|
||||
| `feature/*` | `-dev` | `02.09.01-dev` |
|
||||
| `alpha` | `-alpha` | `02.09.01-alpha` |
|
||||
| `beta` | `-beta` | `02.09.01-beta` |
|
||||
| `rc` | `-rc` | `02.09.01-rc` |
|
||||
|
||||
### Auto version bump
|
||||
|
||||
On every push to `dev`, `feature/*`, or `patch/*`:
|
||||
|
||||
1. Patch version incremented
|
||||
2. Stability suffix `-dev` applied
|
||||
3. All version-bearing files updated (manifests, CHANGELOG, PHP headers, etc.)
|
||||
4. Commit created with `[skip ci]` to avoid loops
|
||||
|
||||
### Release version flow
|
||||
|
||||
Version bumps happen at specific release events:
|
||||
|
||||
| Event | Bump | Example |
|
||||
|-------|------|---------|
|
||||
| Feature merged to dev | Patch bump after dev release | `02.09.01-dev` → release → `02.09.02-dev` |
|
||||
| Dev promoted to RC | Minor bump | `02.09.02-dev` → `02.10.00-rc` |
|
||||
| RC merged to main | Minor bump | `02.10.00-rc` → `02.11.00` (stable) |
|
||||
| Dev recreated from main | Patch bump | `02.11.00` → `02.11.01-dev` |
|
||||
|
||||
### Release stream copies
|
||||
|
||||
When a higher-stability release is published, copies are created for all lesser streams with the same base version:
|
||||
|
||||
- **RC `02.10.00-rc`** also creates: `02.10.00-dev`, `02.10.00-alpha`, `02.10.00-beta`
|
||||
- **Stable `02.11.00`** also creates: `02.11.00-dev`, `02.11.00-alpha`, `02.11.00-beta`, `02.11.00-rc`
|
||||
|
||||
This ensures Joomla sites on ANY stability channel see the update (Joomla only shows versions higher than what's installed).
|
||||
|
||||
### Version files
|
||||
|
||||
The version tools update all files containing version stamps:
|
||||
|
||||
- `.mokogitea/manifest.xml` (canonical source)
|
||||
- Joomla XML manifests (`<version>` tag)
|
||||
- `README.md`, `CHANGELOG.md` (`VERSION:` pattern)
|
||||
- `package.json`, `pyproject.toml`
|
||||
- Any text file with a `VERSION: XX.YY.ZZ` label
|
||||
|
||||
Files synced from other repos (with a `# REPO:` header) are not touched.
|
||||
|
||||
## Code Standards
|
||||
|
||||
- **PHP**: PSR-12, tabs for indentation
|
||||
- **Copyright**: all files must include the Moko Consulting copyright header
|
||||
- **License**: SPDX identifier `GPL-3.0-or-later` (or as specified per repo)
|
||||
- **Attribution**: use `Authored-by: Moko Consulting` in commits, not individual names
|
||||
|
||||
## Commit Messages
|
||||
|
||||
Use conventional commit format:
|
||||
Use [conventional commits](https://www.conventionalcommits.org/):
|
||||
|
||||
```
|
||||
type(scope): short description
|
||||
|
||||
Optional body with context.
|
||||
|
||||
Authored-by: Moko Consulting
|
||||
feat(scope): add new extrafield for invoice tracking
|
||||
fix(sql): correct column type in llx_mytable
|
||||
docs(readme): update installation instructions
|
||||
chore(deps): bump enterprise library to 04.02.30
|
||||
```
|
||||
|
||||
Types: `feat`, `fix`, `chore`, `docs`, `style`, `refactor`, `test`, `ci`
|
||||
**Valid types:** `feat` | `fix` | `docs` | `chore` | `ci` | `refactor` | `style` | `test` | `perf` | `revert` | `build`
|
||||
|
||||
Special flags in commit messages:
|
||||
- `[skip ci]` — skip all CI workflows
|
||||
- `[skip bump]` — skip auto version bump only
|
||||
## Pull Request Workflow
|
||||
|
||||
## Reporting Issues
|
||||
1. **Branch** from `main` using `dev/XX.YY.ZZ/description` format
|
||||
2. **Bump** the patch version in `README.md` before opening the PR
|
||||
3. **Title** must be a valid conventional commit subject line
|
||||
4. **Target** `main` — squash merge only (merge commits are disabled)
|
||||
5. **CI checks** must pass before merge
|
||||
|
||||
Use the repository's issue tracker with the appropriate template.
|
||||
### What Happens on Merge
|
||||
|
||||
When your PR is merged to `main`, these workflows run automatically:
|
||||
|
||||
1. **sync-version-on-merge** — auto-bumps patch version, propagates to all file headers
|
||||
2. **auto-release** — creates `version/XX.YY` branch, git tag, and GitHub Release
|
||||
3. **deploy-demo / deploy-rs** — deploys to demo and RS servers (if `src/**` changed)
|
||||
|
||||
## Coding Standards
|
||||
|
||||
All contributions must follow [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards):
|
||||
|
||||
| Standard | Reference |
|
||||
|----------|-----------|
|
||||
| Coding Style | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) |
|
||||
| File Headers | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) |
|
||||
| Branching | [branch-release-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branch-release-strategy.md) |
|
||||
| Merge Strategy | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) |
|
||||
| Scripting | [scripting-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/scripting-standards.md) |
|
||||
| Build & Release | [build-release.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/workflows/build-release.md) |
|
||||
|
||||
## PR Checklist
|
||||
|
||||
- [ ] Branch named `dev/XX.YY.ZZ/description`
|
||||
- [ ] Patch version bumped in `README.md`
|
||||
- [ ] Conventional commit format for PR title
|
||||
- [ ] All new files have FILE INFORMATION headers
|
||||
- [ ] `declare(strict_types=1)` in all PHP files
|
||||
- [ ] PHPDoc on all public methods
|
||||
- [ ] Tests pass
|
||||
- [ ] CHANGELOG.md updated
|
||||
- [ ] No secrets, tokens, or credentials committed
|
||||
|
||||
## Custom Workflows
|
||||
|
||||
Place repo-specific workflows in `.github/workflows/custom/` — they are **never overwritten or deleted** by MokoStandards sync:
|
||||
|
||||
```
|
||||
.github/workflows/
|
||||
├── deploy-dev.yml ← Synced from MokoStandards
|
||||
├── auto-release.yml ← Synced from MokoStandards
|
||||
└── custom/ ← Your custom workflows (safe)
|
||||
└── my-custom-ci.yml
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
By contributing, you agree that your contributions will be licensed under the [GPL-3.0-or-later](LICENSE) license.
|
||||
|
||||
---
|
||||
|
||||
*Moko Consulting <hello@mokoconsulting.tech>*
|
||||
*This file is synced from [MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards). Do not edit directly — changes will be overwritten on the next sync.*
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
# Extension Configuration
|
||||
EXTENSION_NAME := mokojoomhero
|
||||
EXTENSION_TYPE := template
|
||||
EXTENSION_TYPE := module
|
||||
# Options: module, plugin, component, package, template
|
||||
EXTENSION_VERSION := 1.0.0
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# FILE INFORMATION
|
||||
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
FILE: ./README.md
|
||||
VERSION: 01.00.01
|
||||
VERSION: 01.00.20
|
||||
BRIEF: MokoJoomHero - Joomla Module
|
||||
-->
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ DEFGROUP: [PROJECT_NAME]
|
||||
INGROUP: [PROJECT_NAME].Documentation
|
||||
REPO: [REPOSITORY_URL]
|
||||
PATH: /SECURITY.md
|
||||
VERSION: 04.04.01
|
||||
VERSION: 01.00.20
|
||||
BRIEF: Security vulnerability reporting and handling policy
|
||||
-->
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
<?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
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoJoomHero.Template
|
||||
* INGROUP: MokoJoomHero
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoJoomHero
|
||||
* PATH: /src/component.php
|
||||
* VERSION: 01.00.01
|
||||
* BRIEF: Component-only output — used when ?tmpl=component strips all template chrome
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Document\HtmlDocument;
|
||||
|
||||
/** @var HtmlDocument $this */
|
||||
|
||||
$wa = $this->getWebAssetManager();
|
||||
$wa->usePreset('template.tpl_mokojoomhero');
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<jdoc:include type="metas" />
|
||||
<jdoc:include type="styles" />
|
||||
<jdoc:include type="scripts" />
|
||||
</head>
|
||||
<body class="contentpane component">
|
||||
<jdoc:include type="message" />
|
||||
<jdoc:include type="component" />
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,330 +0,0 @@
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoJoomHero.Template.Assets
|
||||
* INGROUP: MokoJoomHero.Template
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoJoomHero
|
||||
* PATH: /src/css/template.css
|
||||
* VERSION: 01.00.01
|
||||
* BRIEF: Main template stylesheet — base layout, typography, and module chrome
|
||||
*/
|
||||
|
||||
/* ============================================================
|
||||
CSS Custom Properties
|
||||
============================================================ */
|
||||
:root {
|
||||
--brand-color: #1a73e8;
|
||||
--brand-color-dark: #1557b0;
|
||||
--text-color: #333;
|
||||
--text-muted: #666;
|
||||
--bg-color: #fff;
|
||||
--bg-light: #f8f9fa;
|
||||
--border-color: #dee2e6;
|
||||
--header-height: 64px;
|
||||
--sidebar-width: 260px;
|
||||
--container-max: 1200px;
|
||||
--spacing-xs: 0.25rem;
|
||||
--spacing-sm: 0.5rem;
|
||||
--spacing-md: 1rem;
|
||||
--spacing-lg: 2rem;
|
||||
--spacing-xl: 3rem;
|
||||
--radius: 6px;
|
||||
--shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||
--transition: 0.2s ease;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Reset & Base
|
||||
============================================================ */
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
font-size: 1rem;
|
||||
line-height: 1.6;
|
||||
color: var(--text-color);
|
||||
background-color: var(--bg-color);
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--brand-color);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: var(--brand-color-dark);
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Container
|
||||
============================================================ */
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: var(--container-max);
|
||||
margin-inline: auto;
|
||||
padding-inline: var(--spacing-md);
|
||||
}
|
||||
|
||||
.container-fluid {
|
||||
width: 100%;
|
||||
padding-inline: var(--spacing-md);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Header
|
||||
============================================================ */
|
||||
.site-header {
|
||||
background: var(--bg-color);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.site-header.sticky-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.header-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
min-height: var(--header-height);
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.site-brand a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.site-logo {
|
||||
height: 40px;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.site-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 700;
|
||||
color: var(--text-color);
|
||||
}
|
||||
|
||||
.site-description {
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-muted);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Navigation
|
||||
============================================================ */
|
||||
.site-navigation ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.site-navigation a {
|
||||
display: block;
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
color: var(--text-color);
|
||||
border-radius: var(--radius);
|
||||
transition: background var(--transition);
|
||||
}
|
||||
|
||||
.site-navigation a:hover,
|
||||
.site-navigation a.active {
|
||||
background: var(--bg-light);
|
||||
text-decoration: none;
|
||||
color: var(--brand-color);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Topbar
|
||||
============================================================ */
|
||||
.topbar {
|
||||
background: var(--bg-light);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-size: 0.875rem;
|
||||
padding: var(--spacing-xs) 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Hero Section
|
||||
============================================================ */
|
||||
.hero-section {
|
||||
padding: var(--spacing-xl) 0;
|
||||
background: linear-gradient(135deg, var(--brand-color) 0%, var(--brand-color-dark) 100%);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.hero-section h1,
|
||||
.hero-section h2 {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Breadcrumbs
|
||||
============================================================ */
|
||||
.breadcrumbs-area {
|
||||
padding: var(--spacing-sm) 0;
|
||||
background: var(--bg-light);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Main Content Layout
|
||||
============================================================ */
|
||||
.site-main {
|
||||
padding: var(--spacing-lg) 0;
|
||||
min-height: 50vh;
|
||||
}
|
||||
|
||||
.content-area {
|
||||
display: flex;
|
||||
gap: var(--spacing-lg);
|
||||
}
|
||||
|
||||
.content-body {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
flex: 0 0 var(--sidebar-width);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Module Chrome — card style
|
||||
============================================================ */
|
||||
.card {
|
||||
background: var(--bg-color);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius);
|
||||
box-shadow: var(--shadow);
|
||||
margin-bottom: var(--spacing-md);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card .card-header {
|
||||
padding: var(--spacing-md);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.card .card-body {
|
||||
padding: var(--spacing-md);
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Footer
|
||||
============================================================ */
|
||||
.site-footer {
|
||||
background: var(--bg-light);
|
||||
border-top: 1px solid var(--border-color);
|
||||
padding: var(--spacing-lg) 0;
|
||||
margin-top: var(--spacing-xl);
|
||||
}
|
||||
|
||||
.footer-copyright {
|
||||
text-align: center;
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.footer-copyright p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Back to Top
|
||||
============================================================ */
|
||||
.back-to-top {
|
||||
position: fixed;
|
||||
bottom: 2rem;
|
||||
right: 2rem;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: var(--brand-color);
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
text-decoration: none;
|
||||
box-shadow: var(--shadow);
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity var(--transition), visibility var(--transition);
|
||||
z-index: 99;
|
||||
}
|
||||
|
||||
.back-to-top.visible {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.back-to-top:hover {
|
||||
background: var(--brand-color-dark);
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
System Messages
|
||||
============================================================ */
|
||||
.alert {
|
||||
padding: var(--spacing-md);
|
||||
margin-bottom: var(--spacing-md);
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--radius);
|
||||
}
|
||||
|
||||
.alert-message { background: #d1ecf1; border-color: #bee5eb; color: #0c5460; }
|
||||
.alert-warning { background: #fff3cd; border-color: #ffeeba; color: #856404; }
|
||||
.alert-error { background: #f8d7da; border-color: #f5c6cb; color: #721c24; }
|
||||
|
||||
/* ============================================================
|
||||
Responsive
|
||||
============================================================ */
|
||||
@media (max-width: 768px) {
|
||||
.header-inner {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
padding: var(--spacing-sm) 0;
|
||||
}
|
||||
|
||||
.site-navigation ul {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.content-area {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
<?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
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoJoomHero.Template
|
||||
* INGROUP: MokoJoomHero
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoJoomHero
|
||||
* PATH: /src/error.php
|
||||
* VERSION: 01.00.01
|
||||
* BRIEF: Error page template — displayed for 403, 404, 500, etc.
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
/** @var Joomla\CMS\Document\ErrorDocument $this */
|
||||
|
||||
$app = Factory::getApplication();
|
||||
|
||||
// Error details
|
||||
$error_code = $this->error->getCode();
|
||||
$error_message = $this->error->getMessage();
|
||||
|
||||
if (!in_array($error_code, [400, 401, 403, 404, 500])) {
|
||||
$error_code = 500;
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><?php echo $error_code; ?> - <?php echo htmlspecialchars($error_message, ENT_QUOTES, 'UTF-8'); ?></title>
|
||||
<link rel="stylesheet" href="<?php echo Uri::root(true); ?>/templates/tpl_mokojoomhero/css/template.css">
|
||||
<style>
|
||||
.error-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
.error-code {
|
||||
font-size: 6rem;
|
||||
font-weight: 700;
|
||||
color: var(--brand-color, #1a73e8);
|
||||
line-height: 1;
|
||||
margin: 0 0 1rem;
|
||||
}
|
||||
.error-message {
|
||||
font-size: 1.25rem;
|
||||
color: #555;
|
||||
margin: 0 0 2rem;
|
||||
}
|
||||
.error-home {
|
||||
display: inline-block;
|
||||
padding: 0.75rem 1.5rem;
|
||||
background: var(--brand-color, #1a73e8);
|
||||
color: #fff;
|
||||
border-radius: 4px;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.error-home:hover {
|
||||
opacity: 0.85;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="site error-<?php echo $error_code; ?>">
|
||||
<div class="error-page">
|
||||
<p class="error-code"><?php echo $error_code; ?></p>
|
||||
<p class="error-message"><?php echo htmlspecialchars($error_message, ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<a href="<?php echo Uri::base(); ?>" class="error-home">
|
||||
<?php echo Text::_('JERROR_LAYOUT_HOME_PAGE'); ?>
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1 +0,0 @@
|
||||
<!DOCTYPE html><title></title>
|
||||
-181
@@ -1,181 +0,0 @@
|
||||
<?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
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoJoomHero.Template
|
||||
* INGROUP: MokoJoomHero
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoJoomHero
|
||||
* PATH: /src/index.php
|
||||
* VERSION: 01.00.01
|
||||
* BRIEF: Main template entry point — renders the full HTML page
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Document\HtmlDocument;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
/** @var HtmlDocument $this */
|
||||
|
||||
$app = Factory::getApplication();
|
||||
$wa = $this->getWebAssetManager();
|
||||
$params = $app->getTemplate(true)->params;
|
||||
|
||||
// Register and use template assets via Web Asset Manager
|
||||
$wa->usePreset('template.tpl_mokojoomhero');
|
||||
|
||||
// Template parameters
|
||||
$logo = $params->get('logoFile', '');
|
||||
$site_description = $params->get('siteDescription', '');
|
||||
$brand_color = $params->get('brandColor', '#1a73e8');
|
||||
$fluid = (bool) $params->get('fluidContainer', 0);
|
||||
$sticky_header = (bool) $params->get('stickyHeader', 1);
|
||||
$back_to_top = (bool) $params->get('backToTop', 1);
|
||||
|
||||
$container_class = $fluid ? 'container-fluid' : 'container';
|
||||
|
||||
// Inject brand color as CSS custom property
|
||||
$this->addHeadStyle(':root { --brand-color: ' . htmlspecialchars($brand_color, ENT_QUOTES, 'UTF-8') . '; }');
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<jdoc:include type="metas" />
|
||||
<jdoc:include type="styles" />
|
||||
<jdoc:include type="scripts" />
|
||||
</head>
|
||||
<body class="site <?php echo $this->direction === 'rtl' ? 'rtl' : 'ltr'; ?>">
|
||||
<?php // Topbar position ?>
|
||||
<?php if ($this->countModules('topbar')) : ?>
|
||||
<div class="topbar">
|
||||
<div class="<?php echo $container_class; ?>">
|
||||
<jdoc:include type="modules" name="topbar" style="none" />
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php // Header ?>
|
||||
<header class="site-header<?php echo $sticky_header ? ' sticky-header' : ''; ?>">
|
||||
<div class="<?php echo $container_class; ?>">
|
||||
<div class="header-inner">
|
||||
<?php // Site branding ?>
|
||||
<div class="site-brand">
|
||||
<a href="<?php echo Uri::base(); ?>">
|
||||
<?php if ($logo) : ?>
|
||||
<img src="<?php echo htmlspecialchars($logo, ENT_QUOTES, 'UTF-8'); ?>"
|
||||
alt="<?php echo htmlspecialchars($app->get('sitename'), ENT_QUOTES, 'UTF-8'); ?>"
|
||||
class="site-logo" />
|
||||
<?php else : ?>
|
||||
<span class="site-title"><?php echo htmlspecialchars($app->get('sitename'), ENT_QUOTES, 'UTF-8'); ?></span>
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
<?php if ($site_description) : ?>
|
||||
<p class="site-description"><?php echo htmlspecialchars($site_description, ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php // Navigation ?>
|
||||
<?php if ($this->countModules('menu')) : ?>
|
||||
<nav class="site-navigation" aria-label="<?php echo $this->getLanguage()->_('TPL_MOKOJOOMHERO_MAIN_NAV'); ?>">
|
||||
<jdoc:include type="modules" name="menu" style="none" />
|
||||
</nav>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<?php // Banner ?>
|
||||
<?php if ($this->countModules('banner')) : ?>
|
||||
<div class="banner-area">
|
||||
<jdoc:include type="modules" name="banner" style="none" />
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php // Hero section ?>
|
||||
<?php if ($this->countModules('hero')) : ?>
|
||||
<section class="hero-section">
|
||||
<div class="<?php echo $container_class; ?>">
|
||||
<jdoc:include type="modules" name="hero" style="hero" />
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php // Breadcrumbs ?>
|
||||
<?php if ($this->countModules('breadcrumbs')) : ?>
|
||||
<div class="breadcrumbs-area">
|
||||
<div class="<?php echo $container_class; ?>">
|
||||
<jdoc:include type="modules" name="breadcrumbs" style="none" />
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php // Main content area ?>
|
||||
<main class="site-main">
|
||||
<div class="<?php echo $container_class; ?>">
|
||||
<?php if ($this->countModules('main-top')) : ?>
|
||||
<div class="main-top">
|
||||
<jdoc:include type="modules" name="main-top" style="card" />
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="content-area">
|
||||
<?php // Sidebar left ?>
|
||||
<?php if ($this->countModules('sidebar-left')) : ?>
|
||||
<aside class="sidebar sidebar-left" role="complementary">
|
||||
<jdoc:include type="modules" name="sidebar-left" style="card" />
|
||||
</aside>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php // Component output ?>
|
||||
<div class="content-body">
|
||||
<jdoc:include type="message" />
|
||||
<jdoc:include type="component" />
|
||||
</div>
|
||||
|
||||
<?php // Sidebar right ?>
|
||||
<?php if ($this->countModules('sidebar-right')) : ?>
|
||||
<aside class="sidebar sidebar-right" role="complementary">
|
||||
<jdoc:include type="modules" name="sidebar-right" style="card" />
|
||||
</aside>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($this->countModules('main-bottom')) : ?>
|
||||
<div class="main-bottom">
|
||||
<jdoc:include type="modules" name="main-bottom" style="card" />
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<?php // Footer ?>
|
||||
<footer class="site-footer">
|
||||
<div class="<?php echo $container_class; ?>">
|
||||
<?php if ($this->countModules('footer')) : ?>
|
||||
<jdoc:include type="modules" name="footer" style="none" />
|
||||
<?php endif; ?>
|
||||
<div class="footer-copyright">
|
||||
<p>© <?php echo date('Y'); ?> <?php echo htmlspecialchars($app->get('sitename'), ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<?php // Back to top button ?>
|
||||
<?php if ($back_to_top) : ?>
|
||||
<a href="#" class="back-to-top" aria-label="<?php echo $this->getLanguage()->_('TPL_MOKOJOOMHERO_BACK_TO_TOP'); ?>">
|
||||
<span aria-hidden="true">↑</span>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php // Debug position ?>
|
||||
<jdoc:include type="modules" name="debug" style="none" />
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoJoomHero.Template.Assets
|
||||
* INGROUP: MokoJoomHero.Template
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoJoomHero
|
||||
* PATH: /src/js/template.js
|
||||
* VERSION: 01.00.01
|
||||
* BRIEF: Main template JavaScript — back-to-top toggle and lightweight UI helpers
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Back-to-top button visibility toggle
|
||||
var backToTop = document.querySelector('.back-to-top');
|
||||
|
||||
if (backToTop) {
|
||||
window.addEventListener('scroll', function () {
|
||||
if (window.scrollY > 300) {
|
||||
backToTop.classList.add('visible');
|
||||
} else {
|
||||
backToTop.classList.remove('visible');
|
||||
}
|
||||
}, { passive: true });
|
||||
|
||||
backToTop.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
window.scrollTo({ top: 0, behavior: 'smooth' });
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,58 @@
|
||||
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
;
|
||||
; FILE INFORMATION
|
||||
; DEFGROUP: MokoJoomHero.Module.Language
|
||||
; INGROUP: MokoJoomHero.Module
|
||||
; REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
; PATH: /src/language/en-GB/mod_mokojoomhero.ini
|
||||
; VERSION: 01.00.20
|
||||
; BRIEF: Language strings for MokoJoomHero module (frontend + admin form fields)
|
||||
|
||||
MOD_MOKOJOOMHERO_NO_CONTENT="Add content to this module to display it over the hero image."
|
||||
|
||||
; Content fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_CONTENT="Hero Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_LABEL="Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_DESC="HTML content displayed on the hero. Use the editor to add headings, text, buttons, or any HTML."
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_LABEL="Show Card"
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_DESC="Wrap the content in a card with a white background and shadow."
|
||||
|
||||
; Hero mode
|
||||
MOD_MOKOJOOMHERO_MODE_LABEL="Hero Mode"
|
||||
MOD_MOKOJOOMHERO_MODE_DESC="Choose between a slideshow of images or a background video."
|
||||
MOD_MOKOJOOMHERO_MODE_IMAGES="Images"
|
||||
MOD_MOKOJOOMHERO_MODE_VIDEO="Video"
|
||||
|
||||
; Image settings
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_LABEL="Image Folder"
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_DESC="Path to folder containing hero images, relative to Joomla root (e.g. images/heroes)."
|
||||
MOD_MOKOJOOMHERO_IMAGE_COUNT_LABEL="Number of Images"
|
||||
MOD_MOKOJOOMHERO_IMAGE_COUNT_DESC="How many random images to include in the slideshow (1–5)."
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_LABEL="Slide Interval (ms)"
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_DESC="Time between slides in milliseconds (e.g. 5000 = 5 seconds)."
|
||||
|
||||
; Video settings
|
||||
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."
|
||||
|
||||
; 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)."
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_HINT="e.g. 60vh or 400px"
|
||||
|
||||
; Overlay fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_OVERLAY="Overlay & Text"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_LABEL="Overlay Colour"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_DESC="Background colour of the overlay on top of the hero image."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_LABEL="Overlay Opacity"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_DESC="Transparency of the overlay (0 = fully transparent, 1 = fully opaque)."
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_LABEL="Text Alignment"
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_DESC="Horizontal alignment of the overlay text."
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_LABEL="Text Colour"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_DESC="Colour of the text displayed over the hero image."
|
||||
|
||||
; Alignment options
|
||||
MOD_MOKOJOOMHERO_ALIGN_LEFT="Left"
|
||||
MOD_MOKOJOOMHERO_ALIGN_CENTER="Centre"
|
||||
MOD_MOKOJOOMHERO_ALIGN_RIGHT="Right"
|
||||
@@ -0,0 +1,59 @@
|
||||
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
;
|
||||
; FILE INFORMATION
|
||||
; DEFGROUP: MokoJoomHero.Module.Language
|
||||
; INGROUP: MokoJoomHero.Module
|
||||
; REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
; PATH: /src/language/en-GB/mod_mokojoomhero.sys.ini
|
||||
; VERSION: 01.00.20
|
||||
; BRIEF: System language strings — used in admin Extension Manager and Module Manager
|
||||
|
||||
MOD_MOKOJOOMHERO="Module - MokoJoomHero"
|
||||
MOD_MOKOJOOMHERO_DESCRIPTION="Displays a random hero image slideshow or background video with content overlaid. Designed for MokoOnyx template. By Moko Consulting."
|
||||
|
||||
; Content fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_CONTENT="Hero Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_LABEL="Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_DESC="HTML content displayed on the hero. Use the editor to add headings, text, buttons, or any HTML."
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_LABEL="Show Card"
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_DESC="Wrap the content in a card with a white background and shadow."
|
||||
|
||||
; Hero mode
|
||||
MOD_MOKOJOOMHERO_MODE_LABEL="Hero Mode"
|
||||
MOD_MOKOJOOMHERO_MODE_DESC="Choose between a slideshow of images or a background video."
|
||||
MOD_MOKOJOOMHERO_MODE_IMAGES="Images"
|
||||
MOD_MOKOJOOMHERO_MODE_VIDEO="Video"
|
||||
|
||||
; Image settings
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_LABEL="Image Folder"
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_DESC="Path to folder containing hero images, relative to Joomla root (e.g. images/heroes)."
|
||||
MOD_MOKOJOOMHERO_IMAGE_COUNT_LABEL="Number of Images"
|
||||
MOD_MOKOJOOMHERO_IMAGE_COUNT_DESC="How many random images to include in the slideshow (1–5)."
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_LABEL="Slide Interval (ms)"
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_DESC="Time between slides in milliseconds (e.g. 5000 = 5 seconds)."
|
||||
|
||||
; Video settings
|
||||
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."
|
||||
|
||||
; 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)."
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_HINT="e.g. 60vh or 400px"
|
||||
|
||||
; Overlay fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_OVERLAY="Overlay & Text"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_LABEL="Overlay Colour"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_DESC="Background colour of the overlay on top of the hero image."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_LABEL="Overlay Opacity"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_DESC="Transparency of the overlay (0 = fully transparent, 1 = fully opaque)."
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_LABEL="Text Alignment"
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_DESC="Horizontal alignment of the overlay text."
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_LABEL="Text Colour"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_DESC="Colour of the text displayed over the hero image."
|
||||
|
||||
; Alignment options
|
||||
MOD_MOKOJOOMHERO_ALIGN_LEFT="Left"
|
||||
MOD_MOKOJOOMHERO_ALIGN_CENTER="Centre"
|
||||
MOD_MOKOJOOMHERO_ALIGN_RIGHT="Right"
|
||||
@@ -1,13 +0,0 @@
|
||||
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
;
|
||||
; FILE INFORMATION
|
||||
; DEFGROUP: MokoJoomHero.Template.Language
|
||||
; INGROUP: MokoJoomHero.Template
|
||||
; REPO: https://github.com/mokoconsulting-tech/MokoJoomHero
|
||||
; PATH: /src/language/en-GB/tpl_mokojoomhero.ini
|
||||
; VERSION: 01.00.01
|
||||
; BRIEF: Front-end language strings for MokoJoomHero template
|
||||
|
||||
TPL_MOKOJOOMHERO_MAIN_NAV="Main Navigation"
|
||||
TPL_MOKOJOOMHERO_BACK_TO_TOP="Back to top"
|
||||
@@ -1,25 +0,0 @@
|
||||
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
;
|
||||
; FILE INFORMATION
|
||||
; DEFGROUP: MokoJoomHero.Template.Language
|
||||
; INGROUP: MokoJoomHero.Template
|
||||
; REPO: https://github.com/mokoconsulting-tech/MokoJoomHero
|
||||
; PATH: /src/language/en-GB/tpl_mokojoomhero.sys.ini
|
||||
; VERSION: 01.00.01
|
||||
; BRIEF: System language strings — used in admin Extension Manager and Template Manager
|
||||
|
||||
TPL_MOKOJOOMHERO="MokoJoomHero"
|
||||
TPL_MOKOJOOMHERO_DESCRIPTION="A modern, accessible Joomla template by Moko Consulting. Features a hero section, flexible module positions, sticky header, and customisable brand colour."
|
||||
TPL_MOKOJOOMHERO_LOGO_FILE_LABEL="Logo"
|
||||
TPL_MOKOJOOMHERO_LOGO_FILE_DESC="Select an image to use as the site logo."
|
||||
TPL_MOKOJOOMHERO_SITE_DESCRIPTION_LABEL="Site Description"
|
||||
TPL_MOKOJOOMHERO_SITE_DESCRIPTION_DESC="A short tagline displayed next to the logo."
|
||||
TPL_MOKOJOOMHERO_BRAND_COLOR_LABEL="Brand Colour"
|
||||
TPL_MOKOJOOMHERO_BRAND_COLOR_DESC="Primary accent colour used throughout the template."
|
||||
TPL_MOKOJOOMHERO_FLUID_LABEL="Fluid Container"
|
||||
TPL_MOKOJOOMHERO_FLUID_DESC="Use a full-width container instead of a fixed-width one."
|
||||
TPL_MOKOJOOMHERO_STICKY_HEADER_LABEL="Sticky Header"
|
||||
TPL_MOKOJOOMHERO_STICKY_HEADER_DESC="Keep the header visible when scrolling."
|
||||
TPL_MOKOJOOMHERO_BACK_TO_TOP_LABEL="Back to Top Button"
|
||||
TPL_MOKOJOOMHERO_BACK_TO_TOP_DESC="Show a floating button that scrolls the page to the top."
|
||||
@@ -0,0 +1,58 @@
|
||||
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
;
|
||||
; FILE INFORMATION
|
||||
; DEFGROUP: MokoJoomHero.Module.Language
|
||||
; INGROUP: MokoJoomHero.Module
|
||||
; REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
; PATH: /src/language/en-US/mod_mokojoomhero.ini
|
||||
; VERSION: 01.00.20
|
||||
; BRIEF: Language strings for MokoJoomHero module (en-US, frontend + admin form fields)
|
||||
|
||||
MOD_MOKOJOOMHERO_NO_CONTENT="Add content to this module to display it over the hero image."
|
||||
|
||||
; Content fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_CONTENT="Hero Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_LABEL="Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_DESC="HTML content displayed on the hero. Use the editor to add headings, text, buttons, or any HTML."
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_LABEL="Show Card"
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_DESC="Wrap the content in a card with a white background and shadow."
|
||||
|
||||
; Hero mode
|
||||
MOD_MOKOJOOMHERO_MODE_LABEL="Hero Mode"
|
||||
MOD_MOKOJOOMHERO_MODE_DESC="Choose between a slideshow of images or a background video."
|
||||
MOD_MOKOJOOMHERO_MODE_IMAGES="Images"
|
||||
MOD_MOKOJOOMHERO_MODE_VIDEO="Video"
|
||||
|
||||
; Image settings
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_LABEL="Image Folder"
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_DESC="Path to folder containing hero images, relative to Joomla root (e.g. images/heroes)."
|
||||
MOD_MOKOJOOMHERO_IMAGE_COUNT_LABEL="Number of Images"
|
||||
MOD_MOKOJOOMHERO_IMAGE_COUNT_DESC="How many random images to include in the slideshow (1-5)."
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_LABEL="Slide Interval (ms)"
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_DESC="Time between slides in milliseconds (e.g. 5000 = 5 seconds)."
|
||||
|
||||
; Video settings
|
||||
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."
|
||||
|
||||
; 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)."
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_HINT="e.g. 60vh or 400px"
|
||||
|
||||
; Overlay fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_OVERLAY="Overlay & Text"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_LABEL="Overlay Color"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_DESC="Background color of the overlay on top of the hero image."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_LABEL="Overlay Opacity"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_DESC="Transparency of the overlay (0 = fully transparent, 1 = fully opaque)."
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_LABEL="Text Alignment"
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_DESC="Horizontal alignment of the overlay text."
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_LABEL="Text Color"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_DESC="Color of the text displayed over the hero image."
|
||||
|
||||
; Alignment options
|
||||
MOD_MOKOJOOMHERO_ALIGN_LEFT="Left"
|
||||
MOD_MOKOJOOMHERO_ALIGN_CENTER="Center"
|
||||
MOD_MOKOJOOMHERO_ALIGN_RIGHT="Right"
|
||||
@@ -0,0 +1,59 @@
|
||||
; Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||
;
|
||||
; FILE INFORMATION
|
||||
; DEFGROUP: MokoJoomHero.Module.Language
|
||||
; INGROUP: MokoJoomHero.Module
|
||||
; REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
; PATH: /src/language/en-US/mod_mokojoomhero.sys.ini
|
||||
; VERSION: 01.00.20
|
||||
; BRIEF: System language strings — used in admin Extension Manager and Module Manager (en-US)
|
||||
|
||||
MOD_MOKOJOOMHERO="Module - MokoJoomHero"
|
||||
MOD_MOKOJOOMHERO_DESCRIPTION="Displays a random hero image slideshow or background video with content overlaid. Designed for MokoOnyx template. By Moko Consulting."
|
||||
|
||||
; Content fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_CONTENT="Hero Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_LABEL="Content"
|
||||
MOD_MOKOJOOMHERO_CONTENT_DESC="HTML content displayed on the hero. Use the editor to add headings, text, buttons, or any HTML."
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_LABEL="Show Card"
|
||||
MOD_MOKOJOOMHERO_SHOW_CARD_DESC="Wrap the content in a card with a white background and shadow."
|
||||
|
||||
; Hero mode
|
||||
MOD_MOKOJOOMHERO_MODE_LABEL="Hero Mode"
|
||||
MOD_MOKOJOOMHERO_MODE_DESC="Choose between a slideshow of images or a background video."
|
||||
MOD_MOKOJOOMHERO_MODE_IMAGES="Images"
|
||||
MOD_MOKOJOOMHERO_MODE_VIDEO="Video"
|
||||
|
||||
; Image settings
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_LABEL="Image Folder"
|
||||
MOD_MOKOJOOMHERO_IMAGE_FOLDER_DESC="Path to folder containing hero images, relative to Joomla root (e.g. images/heroes)."
|
||||
MOD_MOKOJOOMHERO_IMAGE_COUNT_LABEL="Number of Images"
|
||||
MOD_MOKOJOOMHERO_IMAGE_COUNT_DESC="How many random images to include in the slideshow (1-5)."
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_LABEL="Slide Interval (ms)"
|
||||
MOD_MOKOJOOMHERO_SLIDE_INTERVAL_DESC="Time between slides in milliseconds (e.g. 5000 = 5 seconds)."
|
||||
|
||||
; Video settings
|
||||
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."
|
||||
|
||||
; 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)."
|
||||
MOD_MOKOJOOMHERO_HERO_HEIGHT_HINT="e.g. 60vh or 400px"
|
||||
|
||||
; Overlay fieldset
|
||||
MOD_MOKOJOOMHERO_FIELDSET_OVERLAY="Overlay & Text"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_LABEL="Overlay Color"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_COLOR_DESC="Background color of the overlay on top of the hero image."
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_LABEL="Overlay Opacity"
|
||||
MOD_MOKOJOOMHERO_OVERLAY_OPACITY_DESC="Transparency of the overlay (0 = fully transparent, 1 = fully opaque)."
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_LABEL="Text Alignment"
|
||||
MOD_MOKOJOOMHERO_TEXT_ALIGN_DESC="Horizontal alignment of the overlay text."
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_LABEL="Text Color"
|
||||
MOD_MOKOJOOMHERO_TEXT_COLOR_DESC="Color of the text displayed over the hero image."
|
||||
|
||||
; Alignment options
|
||||
MOD_MOKOJOOMHERO_ALIGN_LEFT="Left"
|
||||
MOD_MOKOJOOMHERO_ALIGN_CENTER="Center"
|
||||
MOD_MOKOJOOMHERO_ALIGN_RIGHT="Right"
|
||||
@@ -0,0 +1,154 @@
|
||||
/* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoJoomHero.Module.Assets
|
||||
* INGROUP: MokoJoomHero.Module
|
||||
* REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
* PATH: /src/css/template.css
|
||||
* VERSION: 01.00.20
|
||||
* BRIEF: Hero module stylesheet — slideshow, video background, overlay
|
||||
*/
|
||||
|
||||
/* ============================================================
|
||||
Hero container
|
||||
============================================================ */
|
||||
.mokojoomhero {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Image slides
|
||||
============================================================ */
|
||||
.mokojoomhero__slide {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
opacity: 0;
|
||||
transition: opacity 1s ease;
|
||||
}
|
||||
|
||||
.mokojoomhero__slide--active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Video background
|
||||
============================================================ */
|
||||
/* Native <video> elements: object-fit works directly */
|
||||
video.mokojoomhero__video {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Embedded <iframe> (YouTube/Vimeo): object-fit doesn't apply to iframes,
|
||||
so we oversize the iframe and centre-crop via the parent's overflow:hidden */
|
||||
iframe.mokojoomhero__video {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 100vw;
|
||||
height: 56.25vw; /* 16:9 aspect ratio */
|
||||
min-height: 100%;
|
||||
min-width: 177.78vh; /* 100 × 16/9 — ensures cover in portrait viewports */
|
||||
transform: translate(-50%, -50%);
|
||||
border: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Overlay
|
||||
============================================================ */
|
||||
.mokojoomhero__overlay {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Content
|
||||
============================================================ */
|
||||
.mokojoomhero__content {
|
||||
max-width: 900px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mokojoomhero__content h1,
|
||||
.mokojoomhero__content h2,
|
||||
.mokojoomhero__content h3 {
|
||||
margin-top: 0;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.mokojoomhero__content p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Card
|
||||
============================================================ */
|
||||
.mokojoomhero__card {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
color: #333;
|
||||
border-radius: 8px;
|
||||
padding: 2rem 2.5rem;
|
||||
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
|
||||
max-width: 700px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.mokojoomhero__card h1,
|
||||
.mokojoomhero__card h2,
|
||||
.mokojoomhero__card h3 {
|
||||
color: #222;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.mokojoomhero__card a:not(.btn) {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
Responsive
|
||||
============================================================ */
|
||||
@media (max-width: 768px) {
|
||||
.mokojoomhero {
|
||||
height: auto !important;
|
||||
}
|
||||
|
||||
.mokojoomhero__video,
|
||||
.mokojoomhero__slide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mokojoomhero__overlay {
|
||||
padding: 1rem;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.mokojoomhero__content {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.mokojoomhero__card {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,28 @@
|
||||
{
|
||||
"$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
|
||||
"name": "tpl_mokojoomhero",
|
||||
"name": "mod_mokojoomhero",
|
||||
"version": "1.0.0",
|
||||
"description": "MokoJoomHero template web assets",
|
||||
"description": "MokoJoomHero module web assets",
|
||||
"license": "GPL-3.0-or-later",
|
||||
"assets": [
|
||||
{
|
||||
"name": "template.tpl_mokojoomhero",
|
||||
"name": "mod_mokojoomhero",
|
||||
"type": "preset",
|
||||
"dependencies": [
|
||||
"template.tpl_mokojoomhero.css",
|
||||
"template.tpl_mokojoomhero.js"
|
||||
"mod_mokojoomhero.css#style",
|
||||
"mod_mokojoomhero.js#script"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "template.tpl_mokojoomhero.css",
|
||||
"name": "mod_mokojoomhero.css",
|
||||
"type": "style",
|
||||
"uri": "css/template.css",
|
||||
"uri": "mod_mokojoomhero/mod_mokojoomhero.css",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"name": "template.tpl_mokojoomhero.js",
|
||||
"name": "mod_mokojoomhero.js",
|
||||
"type": "script",
|
||||
"uri": "js/template.js",
|
||||
"uri": "mod_mokojoomhero/mod_mokojoomhero.js",
|
||||
"version": "1.0.0",
|
||||
"attributes": {
|
||||
"defer": true
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoJoomHero.Module.Assets
|
||||
* INGROUP: MokoJoomHero.Module
|
||||
* REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
* PATH: /src/js/template.js
|
||||
* VERSION: 01.00.20
|
||||
* BRIEF: Hero module JavaScript — image slideshow crossfade
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
// Skip slideshow on mobile — video/images are hidden by CSS
|
||||
if (window.matchMedia('(max-width: 768px)').matches) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ── Image slideshow ──
|
||||
document.querySelectorAll('.mokojoomhero[data-slides]').forEach(function (hero) {
|
||||
var slides = hero.querySelectorAll('.mokojoomhero__slide');
|
||||
var interval = parseInt(hero.dataset.interval, 10) || 5000;
|
||||
var current = 0;
|
||||
|
||||
if (slides.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
setInterval(function () {
|
||||
slides[current].classList.remove('mokojoomhero__slide--active');
|
||||
slides[current].setAttribute('aria-hidden', 'true');
|
||||
|
||||
current = (current + 1) % slides.length;
|
||||
|
||||
slides[current].classList.add('mokojoomhero__slide--active');
|
||||
slides[current].setAttribute('aria-hidden', 'false');
|
||||
}, interval);
|
||||
});
|
||||
|
||||
// ── Pause/resume videos when out of viewport ──
|
||||
if (!('IntersectionObserver' in window)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var observer = new IntersectionObserver(function (entries) {
|
||||
entries.forEach(function (entry) {
|
||||
var hero = entry.target;
|
||||
var video = hero.querySelector('video.mokojoomhero__video');
|
||||
var iframe = hero.querySelector('iframe.mokojoomhero__video');
|
||||
|
||||
if (entry.isIntersecting) {
|
||||
// Resume
|
||||
if (video) {
|
||||
video.play();
|
||||
}
|
||||
if (iframe) {
|
||||
var src = iframe.src || '';
|
||||
if (src.indexOf('youtube') !== -1) {
|
||||
iframe.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
|
||||
} else if (src.indexOf('vimeo') !== -1) {
|
||||
iframe.contentWindow.postMessage('{"method":"play"}', '*');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Pause
|
||||
if (video) {
|
||||
video.pause();
|
||||
}
|
||||
if (iframe) {
|
||||
var src = iframe.src || '';
|
||||
if (src.indexOf('youtube') !== -1) {
|
||||
iframe.contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
|
||||
} else if (src.indexOf('vimeo') !== -1) {
|
||||
iframe.contentWindow.postMessage('{"method":"pause"}', '*');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.1 });
|
||||
|
||||
document.querySelectorAll('.mokojoomhero').forEach(function (hero) {
|
||||
observer.observe(hero);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage mod_mokojoomhero
|
||||
*
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Helper\ModuleHelper;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
/** @var \Joomla\CMS\Application\SiteApplication $app */
|
||||
/** @var \stdClass $module */
|
||||
/** @var \Joomla\Registry\Registry $params */
|
||||
|
||||
// Load module assets via Web Asset Manager (registry in media/mod_mokojoomhero/)
|
||||
$wa = $app->getDocument()->getWebAssetManager();
|
||||
$wa->getRegistry()->addExtensionRegistryFile('mod_mokojoomhero');
|
||||
$wa->usePreset('mod_mokojoomhero');
|
||||
|
||||
// Module parameters
|
||||
$heroMode = $params->get('heroMode', 'images');
|
||||
$imageFolder = $params->get('imageFolder', 'images/heroes');
|
||||
$imageCount = (int) $params->get('imageCount', 5);
|
||||
$slideInterval = (int) $params->get('slideInterval', 5000);
|
||||
$videoFile = $params->get('videoFile', '');
|
||||
$heroHeight = $params->get('heroHeight', '60vh');
|
||||
$overlayColor = $params->get('overlayColor', '#000000');
|
||||
$overlayOpacity = (float) $params->get('overlayOpacity', 0.5);
|
||||
$textAlign = $params->get('textAlign', 'center');
|
||||
$textColor = $params->get('textColor', '#ffffff');
|
||||
$heroContent = $params->get('heroContent', '');
|
||||
$showCard = (bool) $params->get('showCard', 1);
|
||||
|
||||
// Collect hero images
|
||||
$heroImages = [];
|
||||
|
||||
if ($heroMode === 'images') {
|
||||
$folderPath = JPATH_ROOT . '/' . ltrim($imageFolder, '/');
|
||||
|
||||
if (is_dir($folderPath)) {
|
||||
$allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg'];
|
||||
$all = [];
|
||||
|
||||
foreach (new DirectoryIterator($folderPath) as $file) {
|
||||
if ($file->isFile() && in_array(strtolower($file->getExtension()), $allowed, true)) {
|
||||
$all[] = $file->getFilename();
|
||||
}
|
||||
}
|
||||
|
||||
if ($all) {
|
||||
shuffle($all);
|
||||
$picked = array_slice($all, 0, min($imageCount, 5));
|
||||
|
||||
foreach ($picked as $filename) {
|
||||
$heroImages[] = Uri::root() . $imageFolder . '/' . $filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Build video URL — smartly detect YouTube, Vimeo, or local/direct file
|
||||
$videoUrl = '';
|
||||
$youtubeId = '';
|
||||
$vimeoId = '';
|
||||
|
||||
if ($heroMode === 'video' && $videoFile) {
|
||||
// YouTube: watch, embed, shorts, youtu.be, with optional timestamps/params
|
||||
if (preg_match('/(?:youtube\.com\/(?:watch\?.*v=|embed\/|shorts\/|v\/)|youtu\.be\/)([\w-]{11})/', $videoFile, $m)) {
|
||||
$youtubeId = $m[1];
|
||||
// Vimeo: vimeo.com/123456 or player.vimeo.com/video/123456
|
||||
} elseif (preg_match('/vimeo\.com\/(?:video\/)?(\d+)/', $videoFile, $m)) {
|
||||
$vimeoId = $m[1];
|
||||
} else {
|
||||
// Direct URL or local file path
|
||||
$videoUrl = (strpos($videoFile, '://') !== false)
|
||||
? $videoFile
|
||||
: Uri::root() . ltrim($videoFile, '/');
|
||||
}
|
||||
}
|
||||
|
||||
// Module content from the editor (overlay text)
|
||||
$content = $module->content ?? '';
|
||||
|
||||
require ModuleHelper::getLayoutPath('mod_mokojoomhero', $params->get('layout', 'default'));
|
||||
@@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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
|
||||
|
||||
FILE INFORMATION
|
||||
DEFGROUP: MokoJoomHero.Module
|
||||
INGROUP: MokoJoomHero
|
||||
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero
|
||||
PATH: /src/mod_mokojoomhero.xml
|
||||
VERSION: 01.00.20
|
||||
BRIEF: Joomla module manifest — random hero image with content overlay
|
||||
-->
|
||||
<extension type="module" client="site" method="upgrade">
|
||||
<name>Module - MokoJoomHero</name>
|
||||
<creationDate>2026-05</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<copyright>Copyright (C) 2026 Moko Consulting. All rights reserved.</copyright>
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<version>01.00.20-dev</version>
|
||||
<description>Displays a random hero image slideshow or background video with content overlaid. Designed for MokoOnyx template. By Moko Consulting.</description>
|
||||
|
||||
<files>
|
||||
<filename module="mod_mokojoomhero">mod_mokojoomhero.php</filename>
|
||||
<filename>mod_mokojoomhero.xml</filename>
|
||||
<folder>tmpl</folder>
|
||||
<folder>language</folder>
|
||||
</files>
|
||||
|
||||
<media destination="mod_mokojoomhero" folder="media">
|
||||
<filename>joomla.asset.json</filename>
|
||||
<folder>css</folder>
|
||||
<folder>js</folder>
|
||||
</media>
|
||||
|
||||
<languages folder="language">
|
||||
<language tag="en-GB">en-GB/mod_mokojoomhero.ini</language>
|
||||
<language tag="en-GB">en-GB/mod_mokojoomhero.sys.ini</language>
|
||||
<language tag="en-US">en-US/mod_mokojoomhero.ini</language>
|
||||
<language tag="en-US">en-US/mod_mokojoomhero.sys.ini</language>
|
||||
</languages>
|
||||
|
||||
<config>
|
||||
<fields name="params">
|
||||
<fieldset name="basic">
|
||||
<field
|
||||
name="heroMode"
|
||||
type="list"
|
||||
label="MOD_MOKOJOOMHERO_MODE_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_MODE_DESC"
|
||||
default="images"
|
||||
>
|
||||
<option value="images">MOD_MOKOJOOMHERO_MODE_IMAGES</option>
|
||||
<option value="video">MOD_MOKOJOOMHERO_MODE_VIDEO</option>
|
||||
</field>
|
||||
<field
|
||||
name="imageFolder"
|
||||
type="text"
|
||||
label="MOD_MOKOJOOMHERO_IMAGE_FOLDER_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_IMAGE_FOLDER_DESC"
|
||||
default="images/heroes"
|
||||
filter="path"
|
||||
showon="heroMode:images"
|
||||
/>
|
||||
<field
|
||||
name="imageCount"
|
||||
type="number"
|
||||
label="MOD_MOKOJOOMHERO_IMAGE_COUNT_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_IMAGE_COUNT_DESC"
|
||||
default="5"
|
||||
min="1"
|
||||
max="5"
|
||||
showon="heroMode:images"
|
||||
/>
|
||||
<field
|
||||
name="slideInterval"
|
||||
type="number"
|
||||
label="MOD_MOKOJOOMHERO_SLIDE_INTERVAL_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_SLIDE_INTERVAL_DESC"
|
||||
default="5000"
|
||||
min="1000"
|
||||
step="500"
|
||||
showon="heroMode:images"
|
||||
/>
|
||||
<field
|
||||
name="videoFile"
|
||||
type="text"
|
||||
label="MOD_MOKOJOOMHERO_VIDEO_FILE_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_VIDEO_FILE_DESC"
|
||||
filter="string"
|
||||
showon="heroMode:video"
|
||||
/>
|
||||
<field
|
||||
name="heroHeight"
|
||||
type="text"
|
||||
label="MOD_MOKOJOOMHERO_HERO_HEIGHT_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_HERO_HEIGHT_DESC"
|
||||
hint="MOD_MOKOJOOMHERO_HERO_HEIGHT_HINT"
|
||||
default="60vh"
|
||||
filter="string"
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset name="content"
|
||||
label="MOD_MOKOJOOMHERO_FIELDSET_CONTENT"
|
||||
>
|
||||
<field
|
||||
name="heroContent"
|
||||
type="editor"
|
||||
label="MOD_MOKOJOOMHERO_CONTENT_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_CONTENT_DESC"
|
||||
filter="safehtml"
|
||||
buttons="true"
|
||||
hide="readmore,pagebreak"
|
||||
/>
|
||||
<field
|
||||
name="showCard"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="MOD_MOKOJOOMHERO_SHOW_CARD_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_SHOW_CARD_DESC"
|
||||
default="1"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
</fieldset>
|
||||
<fieldset name="advanced"
|
||||
label="MOD_MOKOJOOMHERO_FIELDSET_OVERLAY"
|
||||
>
|
||||
<field
|
||||
name="overlayColor"
|
||||
type="color"
|
||||
label="MOD_MOKOJOOMHERO_OVERLAY_COLOR_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_OVERLAY_COLOR_DESC"
|
||||
default="#000000"
|
||||
/>
|
||||
<field
|
||||
name="overlayOpacity"
|
||||
type="range"
|
||||
label="MOD_MOKOJOOMHERO_OVERLAY_OPACITY_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_OVERLAY_OPACITY_DESC"
|
||||
default="0.5"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.1"
|
||||
/>
|
||||
<field
|
||||
name="textAlign"
|
||||
type="list"
|
||||
label="MOD_MOKOJOOMHERO_TEXT_ALIGN_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_TEXT_ALIGN_DESC"
|
||||
default="center"
|
||||
>
|
||||
<option value="left">MOD_MOKOJOOMHERO_ALIGN_LEFT</option>
|
||||
<option value="center">MOD_MOKOJOOMHERO_ALIGN_CENTER</option>
|
||||
<option value="right">MOD_MOKOJOOMHERO_ALIGN_RIGHT</option>
|
||||
</field>
|
||||
<field
|
||||
name="textColor"
|
||||
type="color"
|
||||
label="MOD_MOKOJOOMHERO_TEXT_COLOR_LABEL"
|
||||
description="MOD_MOKOJOOMHERO_TEXT_COLOR_DESC"
|
||||
default="#ffffff"
|
||||
/>
|
||||
</fieldset>
|
||||
</fields>
|
||||
</config>
|
||||
|
||||
<updateservers>
|
||||
<server type="extension" priority="1" name="MokoJoomHero Updates">
|
||||
https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/main/updates.xml
|
||||
</server>
|
||||
</updateservers>
|
||||
</extension>
|
||||
|
||||
-134
@@ -1,134 +0,0 @@
|
||||
<?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
|
||||
*
|
||||
* FILE INFORMATION
|
||||
* DEFGROUP: MokoJoomHero.Template
|
||||
* INGROUP: MokoJoomHero
|
||||
* REPO: https://github.com/mokoconsulting-tech/MokoJoomHero
|
||||
* PATH: /src/offline.php
|
||||
* VERSION: 01.00.01
|
||||
* BRIEF: Offline page template — shown when the site is taken offline via Global Configuration
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Helper\AuthenticationHelper;
|
||||
use Joomla\CMS\HTML\HTMLHelper;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Router\Route;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
|
||||
/** @var Joomla\CMS\Document\HtmlDocument $this */
|
||||
|
||||
$app = Factory::getApplication();
|
||||
|
||||
// Offline message from Global Configuration
|
||||
$offline_message = $app->get('offline_message', Text::_('JOFFLINE_MESSAGE'));
|
||||
|
||||
// Extra login methods
|
||||
$extra_buttons = AuthenticationHelper::getLoginButtons('form-login');
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="<?php echo $this->language; ?>" dir="<?php echo $this->direction; ?>">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><?php echo htmlspecialchars($app->get('sitename'), ENT_QUOTES, 'UTF-8'); ?> — <?php echo Text::_('JOFFLINE'); ?></title>
|
||||
<link rel="stylesheet" href="<?php echo Uri::root(true); ?>/templates/tpl_mokojoomhero/css/template.css">
|
||||
<jdoc:include type="head" />
|
||||
<style>
|
||||
.offline-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 100vh;
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
}
|
||||
.offline-message {
|
||||
font-size: 1.25rem;
|
||||
color: #555;
|
||||
margin: 0 0 2rem;
|
||||
max-width: 600px;
|
||||
}
|
||||
.offline-login {
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
padding: 2rem;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 8px;
|
||||
}
|
||||
.offline-login .form-group {
|
||||
margin-bottom: 1rem;
|
||||
text-align: left;
|
||||
}
|
||||
.offline-login label {
|
||||
display: block;
|
||||
margin-bottom: 0.25rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.offline-login input[type="text"],
|
||||
.offline-login input[type="password"] {
|
||||
width: 100%;
|
||||
padding: 0.5rem;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.offline-login button {
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
background: var(--brand-color, #1a73e8);
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="site offline">
|
||||
<div class="offline-page">
|
||||
<h1><?php echo htmlspecialchars($app->get('sitename'), ENT_QUOTES, 'UTF-8'); ?></h1>
|
||||
<jdoc:include type="message" />
|
||||
<p class="offline-message"><?php echo htmlspecialchars($offline_message, ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
|
||||
<div class="offline-login">
|
||||
<h2><?php echo Text::_('JLOGIN'); ?></h2>
|
||||
<form action="<?php echo Route::_('index.php', true); ?>" method="post" id="form-login">
|
||||
<div class="form-group">
|
||||
<label for="username"><?php echo Text::_('JGLOBAL_USERNAME'); ?></label>
|
||||
<input type="text" name="username" id="username" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password"><?php echo Text::_('JGLOBAL_PASSWORD'); ?></label>
|
||||
<input type="password" name="password" id="password" required>
|
||||
</div>
|
||||
<button type="submit"><?php echo Text::_('JLOGIN'); ?></button>
|
||||
<input type="hidden" name="option" value="com_users">
|
||||
<input type="hidden" name="task" value="user.login">
|
||||
<input type="hidden" name="return" value="<?php echo base64_encode(Uri::base()); ?>">
|
||||
<?php echo HTMLHelper::_('form.token'); ?>
|
||||
</form>
|
||||
|
||||
<?php if (!empty($extra_buttons)) : ?>
|
||||
<div class="offline-login-extra">
|
||||
<?php foreach ($extra_buttons as $button) : ?>
|
||||
<div class="mt-1">
|
||||
<a class="btn btn-secondary w-100" href="<?php echo $button['url']; ?>">
|
||||
<?php echo htmlspecialchars($button['label'], ENT_QUOTES, 'UTF-8'); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,129 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
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
|
||||
|
||||
FILE INFORMATION
|
||||
DEFGROUP: MokoJoomHero.Template
|
||||
INGROUP: MokoJoomHero
|
||||
REPO: https://github.com/mokoconsulting-tech/MokoJoomHero
|
||||
PATH: /src/templateDetails.xml
|
||||
VERSION: 01.00.01
|
||||
BRIEF: Joomla template manifest — defines metadata, files, positions, and parameters
|
||||
-->
|
||||
<extension type="template" client="site" method="upgrade">
|
||||
<name>tpl_mokojoomhero</name>
|
||||
<creationDate>2026-05</creationDate>
|
||||
<author>Moko Consulting</author>
|
||||
<authorEmail>hello@mokoconsulting.tech</authorEmail>
|
||||
<authorUrl>https://mokoconsulting.tech</authorUrl>
|
||||
<copyright>Copyright (C) 2026 Moko Consulting. All rights reserved.</copyright>
|
||||
<license>GPL-3.0-or-later</license>
|
||||
<version>1.0.0</version>
|
||||
<description>TPL_MOKOJOOMHERO_DESCRIPTION</description>
|
||||
<inheritable>0</inheritable>
|
||||
|
||||
<files>
|
||||
<filename>index.php</filename>
|
||||
<filename>error.php</filename>
|
||||
<filename>offline.php</filename>
|
||||
<filename>component.php</filename>
|
||||
<filename>joomla.asset.json</filename>
|
||||
<filename>templateDetails.xml</filename>
|
||||
<folder>css</folder>
|
||||
<folder>js</folder>
|
||||
<folder>images</folder>
|
||||
<folder>html</folder>
|
||||
<folder>language</folder>
|
||||
</files>
|
||||
|
||||
<media destination="templates/site/tpl_mokojoomhero" folder="media">
|
||||
<folder>css</folder>
|
||||
<folder>js</folder>
|
||||
<folder>images</folder>
|
||||
</media>
|
||||
|
||||
<positions>
|
||||
<position>topbar</position>
|
||||
<position>banner</position>
|
||||
<position>menu</position>
|
||||
<position>hero</position>
|
||||
<position>breadcrumbs</position>
|
||||
<position>sidebar-left</position>
|
||||
<position>sidebar-right</position>
|
||||
<position>main-top</position>
|
||||
<position>main-bottom</position>
|
||||
<position>footer</position>
|
||||
<position>debug</position>
|
||||
</positions>
|
||||
|
||||
<languages folder="language">
|
||||
<language tag="en-GB">en-GB/tpl_mokojoomhero.ini</language>
|
||||
<language tag="en-GB">en-GB/tpl_mokojoomhero.sys.ini</language>
|
||||
</languages>
|
||||
|
||||
<config>
|
||||
<fields name="params">
|
||||
<fieldset name="basic">
|
||||
<field
|
||||
name="logoFile"
|
||||
type="media"
|
||||
label="TPL_MOKOJOOMHERO_LOGO_FILE_LABEL"
|
||||
description="TPL_MOKOJOOMHERO_LOGO_FILE_DESC"
|
||||
/>
|
||||
<field
|
||||
name="siteDescription"
|
||||
type="text"
|
||||
label="TPL_MOKOJOOMHERO_SITE_DESCRIPTION_LABEL"
|
||||
description="TPL_MOKOJOOMHERO_SITE_DESCRIPTION_DESC"
|
||||
filter="string"
|
||||
/>
|
||||
<field
|
||||
name="brandColor"
|
||||
type="color"
|
||||
label="TPL_MOKOJOOMHERO_BRAND_COLOR_LABEL"
|
||||
description="TPL_MOKOJOOMHERO_BRAND_COLOR_DESC"
|
||||
default="#1a73e8"
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset name="advanced">
|
||||
<field
|
||||
name="fluidContainer"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="TPL_MOKOJOOMHERO_FLUID_LABEL"
|
||||
description="TPL_MOKOJOOMHERO_FLUID_DESC"
|
||||
default="0"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
<field
|
||||
name="stickyHeader"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="TPL_MOKOJOOMHERO_STICKY_HEADER_LABEL"
|
||||
description="TPL_MOKOJOOMHERO_STICKY_HEADER_DESC"
|
||||
default="1"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
<field
|
||||
name="backToTop"
|
||||
type="radio"
|
||||
layout="joomla.form.field.radio.switcher"
|
||||
label="TPL_MOKOJOOMHERO_BACK_TO_TOP_LABEL"
|
||||
description="TPL_MOKOJOOMHERO_BACK_TO_TOP_DESC"
|
||||
default="1"
|
||||
>
|
||||
<option value="0">JNO</option>
|
||||
<option value="1">JYES</option>
|
||||
</field>
|
||||
</fieldset>
|
||||
</fields>
|
||||
</config>
|
||||
</extension>
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @package Joomla.Site
|
||||
* @subpackage mod_mokojoomhero
|
||||
*
|
||||
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
|
||||
* @license GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
|
||||
/** @var string $heroMode */
|
||||
/** @var array $heroImages */
|
||||
/** @var int $slideInterval */
|
||||
/** @var string $videoUrl */
|
||||
/** @var string $youtubeId */
|
||||
/** @var string $vimeoId */
|
||||
/** @var string $heroHeight */
|
||||
/** @var string $overlayColor */
|
||||
/** @var float $overlayOpacity */
|
||||
/** @var string $textAlign */
|
||||
/** @var string $textColor */
|
||||
/** @var string $heroContent */
|
||||
/** @var bool $showCard */
|
||||
/** @var string $content */
|
||||
|
||||
$moduleId = 'mod-mokojoomhero-' . $module->id;
|
||||
|
||||
// Convert hex overlay colour to rgba
|
||||
$r = hexdec(substr($overlayColor, 1, 2));
|
||||
$g = hexdec(substr($overlayColor, 3, 2));
|
||||
$b = hexdec(substr($overlayColor, 5, 2));
|
||||
$rgba = "rgba($r, $g, $b, $overlayOpacity)";
|
||||
|
||||
$heightAttr = htmlspecialchars($heroHeight, ENT_QUOTES, 'UTF-8');
|
||||
?>
|
||||
<div id="<?php echo $moduleId; ?>" class="mokojoomhero" style="height: <?php echo $heightAttr; ?>;"
|
||||
<?php if ($heroMode === 'images' && count($heroImages) > 1) : ?>
|
||||
data-slides="<?php echo htmlspecialchars(json_encode($heroImages), ENT_QUOTES, 'UTF-8'); ?>"
|
||||
data-interval="<?php echo $slideInterval; ?>"
|
||||
<?php endif; ?>
|
||||
>
|
||||
<?php // Background layer — single image, slideshow, or video ?>
|
||||
<?php if ($heroMode === 'video' && $youtubeId) : ?>
|
||||
<iframe class="mokojoomhero__video" src="https://www.youtube-nocookie.com/embed/<?php echo htmlspecialchars($youtubeId, ENT_QUOTES, 'UTF-8'); ?>?autoplay=1&mute=1&loop=1&playlist=<?php echo htmlspecialchars($youtubeId, ENT_QUOTES, 'UTF-8'); ?>&controls=0&showinfo=0&rel=0&modestbranding=1&playsinline=1&enablejsapi=1&origin=<?php echo htmlspecialchars(\Joomla\CMS\Uri\Uri::root(), ENT_QUOTES, 'UTF-8'); ?>" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
||||
<?php elseif ($heroMode === 'video' && $vimeoId) : ?>
|
||||
<iframe class="mokojoomhero__video" src="https://player.vimeo.com/video/<?php echo htmlspecialchars($vimeoId, ENT_QUOTES, 'UTF-8'); ?>?autoplay=1&muted=1&loop=1&background=1" allow="autoplay" allowfullscreen></iframe>
|
||||
<?php elseif ($heroMode === 'video' && $videoUrl) : ?>
|
||||
<video class="mokojoomhero__video" autoplay muted loop playsinline>
|
||||
<source src="<?php echo htmlspecialchars($videoUrl, ENT_QUOTES, 'UTF-8'); ?>">
|
||||
</video>
|
||||
<?php elseif ($heroImages) : ?>
|
||||
<?php foreach ($heroImages as $i => $img) : ?>
|
||||
<div class="mokojoomhero__slide<?php echo $i === 0 ? ' mokojoomhero__slide--active' : ''; ?>"
|
||||
style="background-image: url('<?php echo htmlspecialchars($img, ENT_QUOTES, 'UTF-8'); ?>');"
|
||||
aria-hidden="<?php echo $i === 0 ? 'false' : 'true'; ?>">
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?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">
|
||||
<?php if ($module->showtitle) : ?>
|
||||
<h2 class="mokojoomhero__title"><?php echo htmlspecialchars($module->title, ENT_QUOTES, 'UTF-8'); ?></h2>
|
||||
<?php endif; ?>
|
||||
<?php echo $heroContent; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<?php if ($module->showtitle) : ?>
|
||||
<h2 class="mokojoomhero__title"><?php echo htmlspecialchars($module->title, ENT_QUOTES, 'UTF-8'); ?></h2>
|
||||
<?php endif; ?>
|
||||
<?php echo $heroContent; ?>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
+13
-17
@@ -1,17 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Joomla Extension Update Server XML
|
||||
See: https://docs.joomla.org/Deploying_an_Update_Server
|
||||
|
||||
This file is the update server manifest for {{EXTENSION_NAME}}.
|
||||
This file is the update server manifest for mod_mokojoomhero.
|
||||
The Joomla installer polls this URL to check for new versions.
|
||||
|
||||
The manifest.xml in this repository must reference this file:
|
||||
The manifest in this repository must reference this file:
|
||||
<updateservers>
|
||||
<server type="extension" priority="1" name="{{EXTENSION_NAME}}">
|
||||
https://git.mokoconsulting.tech/mokoconsulting-tech/MokoJoomHero/raw/branch/main/update.xml
|
||||
</server>
|
||||
<server type="extension" priority="2" name="{{EXTENSION_NAME}}">
|
||||
https://raw.githubusercontent.com/mokoconsulting-tech/MokoJoomHero/main/update.xml
|
||||
<server type="extension" priority="1" name="MokoJoomHero Updates">
|
||||
https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/main/updates.xml
|
||||
</server>
|
||||
</updateservers>
|
||||
|
||||
@@ -20,20 +18,18 @@
|
||||
-->
|
||||
<updates>
|
||||
<update>
|
||||
<name>{{EXTENSION_NAME}}</name>
|
||||
<description>MokoJoomHero — Moko Consulting Joomla extension</description>
|
||||
<element>{{EXTENSION_ELEMENT}}</element>
|
||||
<type>{{EXTENSION_TYPE}}</type>
|
||||
<name>Module - MokoJoomHero</name>
|
||||
<description>MokoJoomHero — A Joomla hero image module by Moko Consulting</description>
|
||||
<element>mod_mokojoomhero</element>
|
||||
<type>module</type>
|
||||
<client>site</client>
|
||||
<version>{{VERSION}}</version>
|
||||
<downloads>
|
||||
<downloadurl type="full" format="zip">
|
||||
https://git.mokoconsulting.tech/mokoconsulting-tech/MokoJoomHero/releases/download/v{{VERSION}}/{{EXTENSION_ELEMENT}}.zip
|
||||
</downloadurl>
|
||||
<downloadurl type="full" format="zip">
|
||||
https://github.com/mokoconsulting-tech/MokoJoomHero/releases/download/v{{VERSION}}/{{EXTENSION_ELEMENT}}.zip
|
||||
https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/v{{VERSION}}/mod_mokojoomhero.zip
|
||||
</downloadurl>
|
||||
</downloads>
|
||||
<targetplatform name="joomla" version="[56].*"/>
|
||||
<targetplatform name="joomla" version="(5|6).*" />
|
||||
<php_minimum>8.1</php_minimum>
|
||||
</update>
|
||||
</updates>
|
||||
</updates>
|
||||
|
||||
+10
-9
@@ -1,22 +1,23 @@
|
||||
<?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-dev
|
||||
-->
|
||||
|
||||
<?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
|
||||
-->
|
||||
|
||||
<updates>
|
||||
<update>
|
||||
<name>Module - MokoJoomHero</name>
|
||||
<description>Module - MokoJoomHero dev build.</description>
|
||||
<description>Module - MokoJoomHero development build.</description>
|
||||
<element>mod_mokojoomhero</element>
|
||||
<type>module</type>
|
||||
<client>site</client>
|
||||
<version>01.00.20-dev</version>
|
||||
<version>01.00.18-dev</version>
|
||||
<creationDate>2026-05-30</creationDate>
|
||||
<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.20-dev.zip</downloadurl>
|
||||
<downloadurl type='full' format='zip'>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/releases/download/development/mod_mokojoomhero-01.00.18-dev.zip</downloadurl>
|
||||
</downloads>
|
||||
<sha256>a629c54e31bcb6761d709a1b3c384c788172694365922dfad1b737fe502cf6c2</sha256>
|
||||
<tags><tag>dev</tag></tags>
|
||||
<changelogurl>https://git.mokoconsulting.tech/MokoConsulting/MokoJoomHero/raw/branch/main/CHANGELOG.md</changelogurl>
|
||||
<maintainer>Moko Consulting</maintainer>
|
||||
|
||||
Reference in New Issue
Block a user