oliveyrc / orbit_banner
Provides a banner block, with images, video, title, text and link.
README
Orbit Banner is a custom Drupal 11 module that adds banner functionality to the Basic page content type (basic_page).
On install, the module provides:
- Banner media types for images and videos.
- Banner fields on Basic page.
- Form display setup for those fields.
- A
Tabsfield group with aBannertab on the Basic page edit form.
Features
Media types
banner_image(source: image)banner_video(source: video file)
Basic page fields
field_orbit_banner_help(markup help text)field_orbit_banner_title(string)field_orbit_banner_text(formatted text)field_orbit_banner_image(media reference tobanner_image, unlimited)field_orbit_banner_effect(list:slide"Swipe",fade) — shown only when two or more images are selectedfield_orbit_banner_video(media reference tobanner_video)field_orbit_banner_size(list:small,medium,large)field_orbit_banner_parallax(boolean)field_orbit_banner_colour(color field)
Node form layout
The banner fields sit on a Banner vertical tab, split across three horizontal
tabs:
| Tab | Fields |
|---|---|
| Content | title, text, images, video |
| Settings | transition effect, size, parallax, colour |
| Help | the banner help text |
group_tabs, the vertical tab set the Banner tab lives in, is shared with
other modules. field_group nests groups by the parent's children list rather
than each child's parent_name, so the install hook merges the Banner tab into
that list instead of replacing it. Earlier releases replaced it, which silently
dropped sibling tabs such as SEO and Schedule out of the tab set;
_orbit_banner_attach_to_tabs_group() restores any it finds orphaned.
What the block renders
The page_banner block picks one of three templates:
| Condition | Template | Libraries attached |
|---|---|---|
| A video is referenced | orbit-page-banner-video.html.twig |
orbit_banner/video |
| More than one image | orbit-page-banner-slider.html.twig |
orbit_banner/slider (pulls in Swiper) |
| One image, or none | orbit-page-banner.html.twig |
none |
A video always wins over images. The first image is used as the video's poster frame.
Swiper is only requested when a banner actually holds more than one image, so single-image and video banners ship no slideshow JavaScript or CSS.
When no image is set on the node, the block falls back to the field's default
value, then to the banner site settings group, then to the defaults group.
Transition effect
field_orbit_banner_effect chooses between Swiper's slide (labelled "Swipe")
and fade transitions. The default is slide.
Because it only means anything for a slideshow, the field is shown on the node form only once two or more images are selected, using Conditional Fields.
Wiring that up needs two pieces, because the media library widget exposes no input holding the number of selected items and rebuilds itself over AJAX:
OrbitBannerFormHooksadds a hiddenorbit_banner_image_countinput outside the widget's AJAX wrapper, seeded server side, andassets/admin.jskeeps it in step as items are added and removed.- The dependency stored on the form display uses a regex condition
(
^([2-9]|[1-9][0-9]+)$) against a custom selector pointing at that input. It is defined once in\Drupal\orbit_banner\BannerConditions.
Two upstream quirks are worked around, both commented where they are handled:
ConditionalFieldsFormHelper::getState()only builds avaluecondition when the dependee element has a#name. Media library widgets are containers and never get one, soOrbitBannerFormHooks::nameDependeeElement()sets it on whichever element Conditional Fields registered.- Conditional Fields installs its regex comparison from a behaviour marked
weight: -10, but core'sattachBehaviors()ignoresweightand runs behaviours in script load order, so on first paintDrupal.statesruns before the comparison exists and every regex condition evaluates false.assets/admin.jsre-fires the state once to force a correct evaluation.
Parallax
field_orbit_banner_parallax moves the media layer at a slower rate than the
page scroll. It works for all three banner types. The media layer is over-sized
by the travel distance so the transform can never expose an edge, and the extra
size is only applied once the behaviour is running — without JavaScript the
banner is unchanged.
Accessibility
- Video banners have a play/pause button with
aria-controlspointing at the video, and an accessible name that switches between "Play video" and "Pause video" as the media state changes. The state is driven from the media element's ownplayandpauseevents, so it stays correct when playback is blocked by an autoplay policy. - Slideshows use Swiper's a11y module, real
<button>elements for previous and next, and a play/pause button for the autoplay, as required by WCAG 2.2.2 (Pause, Stop, Hide). - Video autoplay, slideshow autoplay, and parallax are all skipped when the
visitor has
prefers-reduced-motion: reduceset. Video autoplay is started from JavaScript rather than theautoplayattribute so this can be honoured.
Colour
field_orbit_banner_colour is exposed to the template as the
--orbit-banner-colour custom property together with a has-colour class, and
tints the gradient overlay that sits above the media.
Requirements
- Drupal
^11 - Contrib modules declared in module info:
color_fieldmarkupmedia_library_editconditional_fieldsfield_grouporbit_mediasite_settings
- Swiper
^11.2atweb/libraries/swiper, but only if you want multi-image banners.
Installing Swiper
The module expects swiper-bundle.min.js and swiper-bundle.min.css at
web/libraries/swiper/. The status report warns when they are missing, and
multi-image banners fall back to showing the first image only.
Composer ignores repositories declared outside the root composer.json, so
add the package to the project root:
composer config repositories.swiper '{"type":"package","package":{"name":"nolimits4web/swiper","version":"11.2.10","type":"drupal-library","license":"MIT","dist":{"type":"tar","url":"https://registry.npmjs.org/swiper/-/swiper-11.2.10.tgz"}}}'
composer require nolimits4web/swiper
Installation
- Ensure required dependencies are available in the site.
- Enable the module:
ddev drush en orbit_banner -y
- Rebuild caches:
ddev drush cr
Updating an existing install
orbit_banner_update_11001()switchesfield_orbit_banner_imageto unlimited cardinality, createsfield_orbit_banner_effectandfield_orbit_banner_parallax, and re-applies the Banner tab layout.orbit_banner_update_11002()attaches the Conditional Fields dependency that hides the transition effect until a second image is added. It requiresconditional_fieldsto be installed first.orbit_banner_update_11003()splits the Banner tab into the Content, Settings and Help horizontal tabs, and re-attaches any sibling tab an earlier release orphaned out ofgroup_tabs.
ddev drush updatedb -y
Verify
- Go to Structure -> Content types -> Basic page -> Manage form display.
- Confirm there is a Tabs group containing a Banner tab, alongside the other tabs the site defines.
- Confirm the Banner tab contains Content, Settings and Help horizontal tabs, with the fields distributed as described above.
- Edit a Basic page. With fewer than two images the Transition effect field is hidden; adding a second image reveals it without a page reload.
- Add two or more images and confirm the banner becomes a slideshow.
Maintainer
- Ricahrd Olivey (oliveyrc)
- Source: https://github.com/oliveyrc/orbit_banner
- Issues: https://github.com/oliveyrc/orbit_banner/issues