Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add hotspot block that can support text, image and video #107

Merged
merged 6 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions blocks/hotspot/hotspot.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/* CSS: styles.css */
.block.hotspot {
position: relative;
background: none;
}

.block.hotspot img {
max-width: 100%;
width: auto;
height: auto;
}

.block.hotspot > div.hotspot {
background: red; /* Temporary for visibility */
z-index: 10; /* Ensure it is above the image */
width: 20px;
height: 20px;
border-radius: 100%;
border: 3px solid white;
position: absolute;
cursor: pointer;
}

.block.hotspot img,
.block.hotspot video {
max-width: 100%;
width: auto;
height: auto;
}

.block.hotspot > div.hotspot .hotspot-content {
display: none; /* Hidden by default */
position: absolute;
top: -10px; /* Adjust positioning as needed */
left: 50%;
transform: translateX(-50%);
padding: 10px;
border-radius: 5px;
z-index: 15;
width: 200px; /* Adjust size as needed */
}

.block.hotspot > div.hotspot .hotspot-content.bgborder {
background: white;
border: 1px solid white;
}

.block.hotspot > div.hotspot.onclick .hotspot-content,
.block.hotspot > div.hotspot:hover .hotspot-content {
display: block; /* Show on click or hover */
}

.block.hotspot > div.hotspot .hotspot-content img,
.block.hotspot > div.hotspot .hotspot-content video {
width: 400px;
height: auto;
max-width: unset;
}

.block.hotspot > div.hotspot .hotspot-content video {
max-height: 150px; /* Adjust as needed */
}

.block.hotspot > div.hotspot:hover::after,
.block.hotspot > div.hotspot.onclick::after {
opacity: 1;
}

main .embed-default {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hostspot block should not influence embed-default styles. no?

position: relative;
left: 0;
width: 100%;
height: 0;
padding-bottom: 56.25%;
}

.block.hotspot svg {
position: absolute;
top: 0;
left: 0;
z-index: 0;
}
53 changes: 53 additions & 0 deletions blocks/hotspot/hotspot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
export default function decorate(block) {
[...block.children].forEach((row, r) => {
if (r > 0) {
const content = [...row.children][0].textContent.trim();
const isImage = content.endsWith('.jpg') || content.endsWith('.png') || content.endsWith('.gif') || content.endsWith('.jpeg');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any image URL can be incorporated as per the requirement. We can use also use regex as per requirement which is upto customisation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes but I am wondering if there's no way of telling the image by just looking at the URL. One option could be to express it as a variant of the block. For e.g. Hotspot(image) , Hotspot(video) etc. and based on that, decide the tag to inject.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will work but then wouldn't it limit the block to either have a specific type of hotspot content (either image or vide )and not a mix of contents.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But yes, I will make the changes for fixed hotspot content.

const isVideo = content.endsWith('.mp4') || content.endsWith('.webm') || content.endsWith('play') || content.endsWith('content/'); // Adjust condition as needed
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous comment.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any video URL can be incorporated as per the requirement. We can use also use regex as per requirement which is upto customisation.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, bit I think there may be cases where just looking at the url may not tell. Maybe need a similar approach like here

const isText = !isImage && !isVideo; // Assuming if it's neither image nor video, it's text

const nexticondiv = document.createElement('div');
nexticondiv.classList.add('hotspot'); // Added class for CSS targeting
nexticondiv.style.left = [...row.children][1].textContent;
nexticondiv.style.top = [...row.children][2].textContent;
nexticondiv.setAttribute('data', content);

// Create content display element
const contentContainer = document.createElement('div');
contentContainer.classList.add('hotspot-content');

if (isImage) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of explicitly adding markup for image, video etc, you could load a fragment and the fragment can contain anything. It'd be more generic. It may be a bit slow though.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is optional btw, and for now we can just support fixed hotspot content.

const img = document.createElement('img');
img.src = content;
contentContainer.appendChild(img);
} else if (isVideo) {
const video = document.createElement('div');
video.innerHTML = `<div class="embed-default">
<iframe src=${content} from allow="encrypted-media" loading="lazy">
</iframe>
</div>`;
// above code can be updated for video controls such as autoplay, loop, etc.
contentContainer.appendChild(video);
} else if (isText) {
contentContainer.textContent = content; // Display text
contentContainer.classList.add('bgborder');
}

// Append content container to hotspot div
nexticondiv.appendChild(contentContainer);
nexticondiv.addEventListener('click', () => {
// Hide content of all other hotspots
document.querySelectorAll('.hotspot').forEach((hotspot) => {
if (hotspot !== nexticondiv) {
hotspot.classList.remove('onclick');
}
});
// Toggle the current hotspot content
nexticondiv.classList.toggle('onclick');
});

row.after(nexticondiv);
row.remove();
}
});
}