
@ -0,0 +1,68 @@ |
|||
document.addEventListener("DOMContentLoaded", function () { |
|||
const toggleSwitch = document.getElementById("view-toggle"); |
|||
const slider = document.getElementById("slider"); |
|||
const container = document.querySelector(".ba-slider"); |
|||
const beforeText = document.getElementById("before-text"); |
|||
const afterText = document.getElementById("after-text"); |
|||
|
|||
// Initialize the state
|
|||
const initializeState = () => { |
|||
slider.value = 0; // Start with "After" at 0%
|
|||
container.style.setProperty("--position", "0%"); |
|||
beforeText.classList.add("text-muted"); |
|||
afterText.classList.remove("text-muted"); |
|||
toggleSwitch.setAttribute("aria-checked", "true"); |
|||
}; |
|||
|
|||
// Function to animate the slider
|
|||
const animateSlider = (start, end, duration = 350) => { |
|||
const stepTime = 10; // Step interval in ms
|
|||
const steps = duration / stepTime; |
|||
const stepValue = (end - start) / steps; |
|||
let currentValue = start; |
|||
let currentStep = 0; |
|||
|
|||
const interval = setInterval(() => { |
|||
currentStep++; |
|||
currentValue += stepValue; |
|||
slider.value = currentValue; |
|||
container.style.setProperty("--position", `${currentValue}%`); |
|||
|
|||
if (currentStep >= steps) { |
|||
clearInterval(interval); |
|||
slider.value = end; // Ensure it ends exactly at the target
|
|||
container.style.setProperty("--position", `${end}%`); |
|||
} |
|||
}, stepTime); |
|||
}; |
|||
|
|||
// Function to handle slider position when toggling
|
|||
const handleToggle = () => { |
|||
const isChecked = toggleSwitch.checked; |
|||
|
|||
if (isChecked) { |
|||
// Show "After" view
|
|||
animateSlider(parseFloat(slider.value), 0); // Animate to 0% (After)
|
|||
beforeText.classList.add("text-muted"); |
|||
afterText.classList.remove("text-muted"); |
|||
toggleSwitch.setAttribute("aria-checked", "true"); |
|||
} else { |
|||
// Show "Before" view
|
|||
animateSlider(parseFloat(slider.value), 100); // Animate to 100% (Before)
|
|||
afterText.classList.add("text-muted"); |
|||
beforeText.classList.remove("text-muted"); |
|||
toggleSwitch.setAttribute("aria-checked", "false"); |
|||
} |
|||
}; |
|||
|
|||
// Initialize the state on page load
|
|||
initializeState(); |
|||
|
|||
// Add event listener for the switch toggle
|
|||
toggleSwitch.addEventListener("change", handleToggle); |
|||
|
|||
// Add slider logic (if manual adjustment is still needed)
|
|||
slider.addEventListener("input", (e) => { |
|||
container.style.setProperty("--position", `${e.target.value}%`); |
|||
}); |
|||
}); |
@ -0,0 +1,95 @@ |
|||
+++ |
|||
layout = "work/single" |
|||
featured = true |
|||
theme = "light" |
|||
background = "#E7F5FF" |
|||
accent = "#005F9C" |
|||
text = "#212529" |
|||
title = "OONI Illustration System" |
|||
summary = "We created a modular illustration system for OONI making it easy for both designers and non-designers to craft their own illustrations, bringing the OONIverse to life." |
|||
date = "2024-12-16 12:00:00 +0200" |
|||
images = ["img/work/ooni-illustration-system.webp", "ooni-illustration-system"] |
|||
tags = [] |
|||
categories = ["Illustrations"] |
|||
[links] |
|||
"OONI Website" = "https://ooni.org" |
|||
"Outreach Kit" = "https://ooni.org/support/ooni-outreach-kit/" |
|||
+++ |
|||
|
|||
{{< figure src="/img/work/ooni-cover.webp" alt="OONI Illustration System" >}} |
|||
|
|||
## OONI’s Mission |
|||
|
|||
OONI, or the Open Observatory of Network Interference, is an open source project dedicated to measuring internet censorship worldwide. Their work is vital for documenting and understanding the landscape of internet freedom, particularly in regions where access to information is controlled or restricted by governments or other entities. |
|||
|
|||
## Our Approach and Objectives |
|||
|
|||
OONI’s tools offer crucial insights into internet censorship, but the information can sometimes feel dense and hard to navigate. This can make it tough for users to fully engage and understand its implications. |
|||
|
|||
To address this, we used illustrations to clarify the content, making it more engaging and dynamic. Our goal was to transform OONI’s website, tools, and promotional materials into resources that are both informative and inviting, helping their diverse, global audience understand and connect with the information more easily. |
|||
|
|||
## Redesigning the Mascot |
|||
|
|||
OONI’s original mascot played a vital role in their brand identity, but they needed a more streamlined design that could be easily adapted and used in different settings. |
|||
|
|||
{{< ba-slider |
|||
before_light="/img/work/ooni-mascot-before.svg" |
|||
before_dark="/img/work/ooni-mascot-before-dark.svg" |
|||
before_nojs="/img/work/ooni-mascot-before.webp" |
|||
after_light="/img/work/ooni-mascot-after.svg" |
|||
after_dark="/img/work/ooni-mascot-after-dark.svg" |
|||
after_nojs="/img/work/ooni-mascot-after.webp" |
|||
>}} |
|||
|
|||
## Refined Design |
|||
|
|||
The new mascot features a simplified design with a balanced look, making it more adaptable to different environments. |
|||
|
|||
**Streamlined Aesthetic**: We removed the suction cup details from the tentacles and adjusted their spread, ensuring a consistent appearance in every use. |
|||
|
|||
**Modular Components**: The mascot includes a separate head and four movable tentacles that can be adjusted or rearranged independently. |
|||
|
|||
**Versatility**: This modular design allows for a wide range of combinations and poses, making the mascot adaptable to many different scenarios. |
|||
|
|||
{{< figure class="with-js d-lg-block d-none" src="/img/work/ooni-octopus-tentacles.svg" alt="OONI octopus tentacles" >}} |
|||
{{< figure class="with-js d-block d-lg-none" src="/img/work/ooni-octopus-tentacles-mobile.svg" alt="OONI octopus tentacles" >}} |
|||
|
|||
{{< figure class="no-js d-lg-block d-none" src="/img/work/ooni-octopus-tentacles.webp" alt="OONI octopus tentacles" >}} |
|||
{{< figure class="no-js d-block d-lg-none" src="/img/work/ooni-octopus-tentacles-mobile.webp" alt="OONI octopus tentacles" >}} |
|||
|
|||
## Refining the Tentacles |
|||
|
|||
The octopus is the central figure in the OONIverse, notable for its complexity and flexibility. With modular parts like the head, neck, and four tentacles, and 2,496 possible tentacle combinations, it offers a rich variety of visual expressions and potential uses across different contexts. |
|||
|
|||
Designing the mascot’s tentacles presented several challenges. The primary goal was to create a stable structure that kept all elements intact while allowing for various combinations. Striking the right balance between organic and geometric shapes was crucial to ensure the design was both modern and reflective of underwater life. |
|||
|
|||
{{< figure class="with-js" src="/img/work/ooni-tentacles.svg" alt="OONI octopus tentacles" >}} |
|||
{{< figure class="no-js" src="/img/work/ooni-tentacles.webp" alt="OONI octopus tentacles" >}} |
|||
|
|||
## Adding Emotional Depth |
|||
|
|||
Adding an array of emotions brought the characters to life, infusing them with personality and expression. We designed a range of expressions, including neutral, bored, excited, shy, and angry, to cover the main emotions the character would need. This variety ensures that the mascot is vivid, lifelike, and approachable, making it easier to connect with and engage the audience. |
|||
|
|||
{{< lottie src="https://lottie.host/79ec3797-da81-4e42-8260-cb907ddbfa67/TyiAKnh6SA.json" loop="true" autoplay="true" controls="true" >}} |
|||
|
|||
## Expanding the OONIverse |
|||
|
|||
Once the mascot was ready, we set out to build a world for them to explore. Using a similar modular approach, we developed two additional characters: the fish and the eel, each with its own set of components and variations. We also created scenes or ‘play sets’ featuring interchangeable elements like seaweed and various ‘underwater’ shapes, allowing for the creation of lively and dynamic scenes, including different color modes for different depths of the ocean. |
|||
|
|||
{{< figure src="/img/work/ooni-ooniverse.webp" alt="OONIverse" >}} |
|||
|
|||
## Managing Design Elements with Precision |
|||
|
|||
To manage the various elements of each character and scene, we developed a comprehensive design system that organizes all the components and variations. A key aspect of this system is the use of Figma variables to create color options for each illustration component. This approach allows the creatures to change colors with just one click, offering six different color collections, each with 3-4 color modes. |
|||
|
|||
{{< figure src="/img/work/ooni-precision.webp" alt="OONI design elements" >}} |
|||
|
|||
## How we helped |
|||
|
|||
**Custom Illustration System**: We designed a modular illustration system that allows both designers and non-designers to easily create custom visuals. |
|||
|
|||
**Simplified Mascot**: We streamlined the mascot’s design for improved adaptability and introduced a range of emotions to keep it engaging and relatable across different scenarios. |
|||
|
|||
**Enhanced Accessibility**: We created visuals that align with WCAG 2.2 guidelines, making OONI’s content more accessible for their diverse global audience. |
|||
|
|||
**Cohesive Design System**: We built a cohesive design system that streamlines the creation process, offering flexibility and consistency for designers and non designers alike. |
@ -0,0 +1,95 @@ |
|||
+++ |
|||
layout = "work/single" |
|||
featured = true |
|||
theme = "light" |
|||
background = "#E7F5FF" |
|||
accent = "#005F9C" |
|||
text = "#212529" |
|||
title = "OONI Illustration System" |
|||
summary = "We created a modular illustration system for OONI making it easy for both designers and non-designers to craft their own illustrations, bringing the OONIverse to life." |
|||
date = "2024-12-16 12:00:00 +0200" |
|||
images = ["img/work/ooni-illustration-system.webp", "ooni-illustration-system"] |
|||
tags = [] |
|||
categories = ["Illustrations"] |
|||
[links] |
|||
"OONI Website" = "https://ooni.org" |
|||
"Outreach Kit" = "https://ooni.org/support/ooni-outreach-kit/" |
|||
+++ |
|||
|
|||
{{< figure src="/img/work/ooni-cover.webp" alt="OONI Illustration System" >}} |
|||
|
|||
## OONI’s Mission |
|||
|
|||
OONI, or the Open Observatory of Network Interference, is an open source project dedicated to measuring internet censorship worldwide. Their work is vital for documenting and understanding the landscape of internet freedom, particularly in regions where access to information is controlled or restricted by governments or other entities. |
|||
|
|||
## Our Approach and Objectives |
|||
|
|||
OONI’s tools offer crucial insights into internet censorship, but the information can sometimes feel dense and hard to navigate. This can make it tough for users to fully engage and understand its implications. |
|||
|
|||
To address this, we used illustrations to clarify the content, making it more engaging and dynamic. Our goal was to transform OONI’s website, tools, and promotional materials into resources that are both informative and inviting, helping their diverse, global audience understand and connect with the information more easily. |
|||
|
|||
## Redesigning the Mascot |
|||
|
|||
OONI’s original mascot played a vital role in their brand identity, but they needed a more streamlined design that could be easily adapted and used in different settings. |
|||
|
|||
{{< ba-slider |
|||
before_light="/img/work/ooni-mascot-before.svg" |
|||
before_dark="/img/work/ooni-mascot-before-dark.svg" |
|||
before_nojs="/img/work/ooni-mascot-before.webp" |
|||
after_light="/img/work/ooni-mascot-after.svg" |
|||
after_dark="/img/work/ooni-mascot-after-dark.svg" |
|||
after_nojs="/img/work/ooni-mascot-after.webp" |
|||
>}} |
|||
|
|||
## Refined Design |
|||
|
|||
The new mascot features a simplified design with a balanced look, making it more adaptable to different environments. |
|||
|
|||
**Streamlined Aesthetic**: We removed the suction cup details from the tentacles and adjusted their spread, ensuring a consistent appearance in every use. |
|||
|
|||
**Modular Components**: The mascot includes a separate head and four movable tentacles that can be adjusted or rearranged independently. |
|||
|
|||
**Versatility**: This modular design allows for a wide range of combinations and poses, making the mascot adaptable to many different scenarios. |
|||
|
|||
{{< figure class="with-js d-lg-block d-none" src="/img/work/ooni-octopus-tentacles.svg" alt="OONI octopus tentacles" >}} |
|||
{{< figure class="with-js d-block d-lg-none" src="/img/work/ooni-octopus-tentacles-mobile.svg" alt="OONI octopus tentacles" >}} |
|||
|
|||
{{< figure class="no-js d-lg-block d-none" src="/img/work/ooni-octopus-tentacles.webp" alt="OONI octopus tentacles" >}} |
|||
{{< figure class="no-js d-block d-lg-none" src="/img/work/ooni-octopus-tentacles-mobile.webp" alt="OONI octopus tentacles" >}} |
|||
|
|||
## Refining the Tentacles |
|||
|
|||
The octopus is the central figure in the OONIverse, notable for its complexity and flexibility. With modular parts like the head, neck, and four tentacles, and 2,496 possible tentacle combinations, it offers a rich variety of visual expressions and potential uses across different contexts. |
|||
|
|||
Designing the mascot’s tentacles presented several challenges. The primary goal was to create a stable structure that kept all elements intact while allowing for various combinations. Striking the right balance between organic and geometric shapes was crucial to ensure the design was both modern and reflective of underwater life. |
|||
|
|||
{{< figure class="with-js" src="/img/work/ooni-tentacles.svg" alt="OONI octopus tentacles" >}} |
|||
{{< figure class="no-js" src="/img/work/ooni-tentacles.webp" alt="OONI octopus tentacles" >}} |
|||
|
|||
## Adding Emotional Depth |
|||
|
|||
Adding an array of emotions brought the characters to life, infusing them with personality and expression. We designed a range of expressions, including neutral, bored, excited, shy, and angry, to cover the main emotions the character would need. This variety ensures that the mascot is vivid, lifelike, and approachable, making it easier to connect with and engage the audience. |
|||
|
|||
{{< lottie src="https://lottie.host/79ec3797-da81-4e42-8260-cb907ddbfa67/TyiAKnh6SA.json" loop="true" autoplay="true" controls="true" >}} |
|||
|
|||
## Expanding the OONIverse |
|||
|
|||
Once the mascot was ready, we set out to build a world for them to explore. Using a similar modular approach, we developed two additional characters: the fish and the eel, each with its own set of components and variations. We also created scenes or ‘play sets’ featuring interchangeable elements like seaweed and various ‘underwater’ shapes, allowing for the creation of lively and dynamic scenes, including different color modes for different depths of the ocean. |
|||
|
|||
{{< figure src="/img/work/ooni-ooniverse.webp" alt="OONIverse" >}} |
|||
|
|||
## Managing Design Elements with Precision |
|||
|
|||
To manage the various elements of each character and scene, we developed a comprehensive design system that organizes all the components and variations. A key aspect of this system is the use of Figma variables to create color options for each illustration component. This approach allows the creatures to change colors with just one click, offering six different color collections, each with 3-4 color modes. |
|||
|
|||
{{< figure src="/img/work/ooni-precision.webp" alt="OONI design elements" >}} |
|||
|
|||
## How we helped |
|||
|
|||
**Custom Illustration System**: We designed a modular illustration system that allows both designers and non-designers to easily create custom visuals. |
|||
|
|||
**Simplified Mascot**: We streamlined the mascot’s design for improved adaptability and introduced a range of emotions to keep it engaging and relatable across different scenarios. |
|||
|
|||
**Enhanced Accessibility**: We created visuals that align with WCAG 2.2 guidelines, making OONI’s content more accessible for their diverse global audience. |
|||
|
|||
**Cohesive Design System**: We built a cohesive design system that streamlines the creation process, offering flexibility and consistency for designers and non designers alike. |
@ -0,0 +1,211 @@ |
|||
<div class="ba-slider-container"> |
|||
<div class="ba-slider" style="--position: 0%;" role="region" aria-labelledby="slider"> |
|||
<div class="image-container"> |
|||
<div class="image-before slider-image"> |
|||
<!-- Before Image (Desktop) --> |
|||
{{ if .Params.before_light_desktop }} |
|||
<figure class="with-js on-light d-lg-block d-none"> |
|||
<img src="{{ .Params.before_light_desktop }}" alt="Before Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ else if .Params.before_light }} |
|||
<figure class="with-js on-light d-lg-block d-none"> |
|||
<img src="{{ .Params.before_light }}" alt="Before Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ end }} |
|||
|
|||
{{ if .Params.before_dark_desktop }} |
|||
<figure class="with-js on-dark d-lg-block d-none"> |
|||
<img src="{{ .Params.before_dark_desktop }}" alt="Before Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ else if .Params.before_dark }} |
|||
<figure class="with-js on-dark d-lg-block d-none"> |
|||
<img src="{{ .Params.before_dark }}" alt="Before Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ end }} |
|||
|
|||
{{ if .Params.before_nojs_desktop }} |
|||
<figure class="no-js d-lg-block d-none"> |
|||
<img src="{{ .Params.before_nojs_desktop }}" alt="Before Image"> |
|||
</figure> |
|||
{{ else if .Params.before_nojs }} |
|||
<figure class="no-js d-lg-block d-none"> |
|||
<img src="{{ .Params.before_nojs }}" alt="Before Image"> |
|||
</figure> |
|||
{{ end }} |
|||
|
|||
<!-- Before Image (Mobile) --> |
|||
{{ if .Params.before_light_mobile }} |
|||
<figure class="with-js on-light d-block d-lg-none"> |
|||
<img src="{{ .Params.before_light_mobile }}" alt="Before Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ else if .Params.before_light }} |
|||
<figure class="with-js on-light d-block d-lg-none"> |
|||
<img src="{{ .Params.before_light }}" alt="Before Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ end }} |
|||
|
|||
{{ if .Params.before_dark_mobile }} |
|||
<figure class="with-js on-dark d-block d-lg-none"> |
|||
<img src="{{ .Params.before_dark_mobile }}" alt="Before Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ else if .Params.before_dark }} |
|||
<figure class="with-js on-dark d-block d-lg-none"> |
|||
<img src="{{ .Params.before_dark }}" alt="Before Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ end }} |
|||
|
|||
{{ if .Params.before_nojs_mobile }} |
|||
<figure class="no-js d-block d-lg-none"> |
|||
<img src="{{ .Params.before_nojs_mobile }}" alt="Before Image"> |
|||
</figure> |
|||
{{ else if .Params.before_nojs }} |
|||
<figure class="no-js d-block d-lg-none"> |
|||
<img src="{{ .Params.before_nojs }}" alt="Before Image"> |
|||
</figure> |
|||
{{ end }} |
|||
</div> |
|||
|
|||
<div class="image-after slider-image"> |
|||
<!-- After Image (Desktop) --> |
|||
{{ if .Params.after_light_desktop }} |
|||
<figure class="with-js on-light d-lg-block d-none"> |
|||
<img src="{{ .Params.after_light_desktop }}" alt="After Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ else if .Params.after_light }} |
|||
<figure class="with-js on-light d-lg-block d-none"> |
|||
<img src="{{ .Params.after_light }}" alt="After Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ end }} |
|||
|
|||
{{ if .Params.after_dark_desktop }} |
|||
<figure class="with-js on-dark d-lg-block d-none"> |
|||
<img src="{{ .Params.after_dark_desktop }}" alt="After Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ else if .Params.after_dark }} |
|||
<figure class="with-js on-dark d-lg-block d-none"> |
|||
<img src="{{ .Params.after_dark }}" alt="After Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ end }} |
|||
|
|||
{{ if .Params.after_nojs_desktop }} |
|||
<figure class="no-js d-lg-block d-none"> |
|||
<img src="{{ .Params.after_nojs_desktop }}" alt="After Image"> |
|||
</figure> |
|||
{{ else if .Params.after_nojs }} |
|||
<figure class="no-js d-lg-block d-none"> |
|||
<img src="{{ .Params.after_nojs }}" alt="After Image"> |
|||
</figure> |
|||
{{ end }} |
|||
|
|||
<!-- After Image (Mobile) --> |
|||
{{ if .Params.after_light_mobile }} |
|||
<figure class="with-js on-light d-block d-lg-none"> |
|||
<img src="{{ .Params.after_light_mobile }}" alt="After Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ else if .Params.after_light }} |
|||
<figure class="with-js on-light d-block d-lg-none"> |
|||
<img src="{{ .Params.after_light }}" alt="After Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ end }} |
|||
|
|||
{{ if .Params.after_dark_mobile }} |
|||
<figure class="with-js on-dark d-block d-lg-none"> |
|||
<img src="{{ .Params.after_dark_mobile }}" alt="After Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ else if .Params.after_dark }} |
|||
<figure class="with-js on-dark d-block d-lg-none"> |
|||
<img src="{{ .Params.after_dark }}" alt="After Image" |
|||
style="background-color: {{ .Page.Params.background }};"> |
|||
</figure> |
|||
{{ end }} |
|||
|
|||
{{ if .Params.after_nojs_mobile }} |
|||
<figure class="no-js d-block d-lg-none"> |
|||
<img src="{{ .Params.after_nojs_mobile }}" alt="After Image"> |
|||
</figure> |
|||
{{ else if .Params.after_nojs }} |
|||
<figure class="no-js d-block d-lg-none"> |
|||
<img src="{{ .Params.after_nojs }}" alt="After Image"> |
|||
</figure> |
|||
{{ end }} |
|||
</div> |
|||
</div> |
|||
|
|||
<input id="slider" type="range" min="0" max="100" value="0" aria-label="Adjust before and after view slider" |
|||
class="slider" /> |
|||
<div class="slider-line" aria-hidden="true"></div> |
|||
<div class="slider-button" aria-hidden="true"> |
|||
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" fill="currentColor" viewBox="0 0 256 256"> |
|||
<rect width="256" height="256" fill="none"></rect> |
|||
<line x1="128" y1="40" x2="128" y2="216" fill="none" stroke="currentColor" stroke-linecap="round" |
|||
stroke-linejoin="round" stroke-width="16"></line> |
|||
<line x1="96" y1="128" x2="16" y2="128" fill="none" stroke="currentColor" stroke-linecap="round" |
|||
stroke-linejoin="round" stroke-width="16"></line> |
|||
<polyline points="48 160 16 128 48 96" fill="none" stroke="currentColor" stroke-linecap="round" |
|||
stroke-linejoin="round" stroke-width="16"></polyline> |
|||
<line x1="160" y1="128" x2="240" y2="128" fill="none" stroke="currentColor" stroke-linecap="round" |
|||
stroke-linejoin="round" stroke-width="16"></line> |
|||
<polyline points="208 96 240 128 208 160" fill="none" stroke="currentColor" stroke-linecap="round" |
|||
stroke-linejoin="round" stroke-width="16"></polyline> |
|||
</svg> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<script> |
|||
document.addEventListener('DOMContentLoaded', () => { |
|||
const lottiePlayer = document.querySelector('lottie-player'); |
|||
|
|||
if (lottiePlayer) { |
|||
const shadowRoot = lottiePlayer.shadowRoot; |
|||
const toolbar = shadowRoot.querySelector('.toolbar'); |
|||
|
|||
if (toolbar) { |
|||
toolbar.style.justifyContent = 'center'; |
|||
toolbar.style.gap = '0.5rem'; |
|||
} else { |
|||
console.log('Toolbar not found inside shadow DOM.'); |
|||
} |
|||
} else { |
|||
console.error('lottie-player element not found.'); |
|||
} |
|||
}); |
|||
</script> |
|||
|
|||
<div class="d-flex justify-content-center align-items-center gap-2" role="group" aria-label="Toggle between Before and After views"> |
|||
<span class="fw-semibold text-muted" id="before-text">Before</span> |
|||
<label class="form-switch position-relative d-inline-block"> |
|||
<input |
|||
type="checkbox" |
|||
class="form-check-input visually-hidden" |
|||
id="view-toggle" |
|||
checked |
|||
aria-checked="true" |
|||
aria-labelledby="before-text after-text" |
|||
aria-describedby="toggle-description" |
|||
> |
|||
<span class="switch-slider rounded-pill"></span> |
|||
</label> |
|||
<span class="fw-semibold" id="after-text">After</span> |
|||
</div> |
|||
<p id="toggle-description" class="visually-hidden"> |
|||
Use this toggle to switch between the Before and After views of the slider. |
|||
</p> |
|||
|
|||
{{ $js := resources.Get "js/before-after-slider.js" | resources.Minify }} |
|||
<script src="{{ $js.RelPermalink }}"></script> |
@ -0,0 +1,23 @@ |
|||
{{ $lottieScript := resources.Get "js/lottie-player.js" | resources.Minify }} |
|||
<script src="{{ $lottieScript.RelPermalink }}"></script> |
|||
|
|||
<lottie-player |
|||
src="{{ .Get "src" | relURL }}" |
|||
background="{{ .Get "background" | default "transparent" }}" |
|||
speed="{{ .Get "speed" | default "1" }}" |
|||
{{ if .Get "loop" }}loop{{ end }} |
|||
{{ if .Get "controls" }}controls{{ end }} |
|||
{{ if .Get "autoplay" }}autoplay{{ end }}> |
|||
</lottie-player> |
|||
|
|||
<style> |
|||
lottie-player { |
|||
height: 300px; |
|||
max-width: 100%; |
|||
max-height: 100%; |
|||
--lottie-player-seeker-display: none; |
|||
--lottie-player-toolbar-icon-color: #999; |
|||
--lottie-player-toolbar-icon-hover-color: #555; |
|||
--lottie-player-toolbar-icon-active-color: #222; |
|||
} |
|||
</style> |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 7.5 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 40 KiB |
After Width: | Height: | Size: 8.6 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 8.5 KiB |