Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
381 changes: 381 additions & 0 deletions app/views/articles/_fullscreen_embed.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,381 @@
<style>
/* Fullscreen embed specific styles */
#article-body {
position: fixed;
top: 55px;
left: 0;
width: 100vw;
height: 100vh;
background: var(--base-0);
z-index: 100;
overflow: hidden;
}

/* Actions sidebar - fixed left position */
#article-body .crayons-layout__sidebar-left {
position: fixed;
left: 10px;
top: 55px;
width: 50px;
height: calc(100vh - 55px);
border-right: 0;
padding-top: 20px;
overflow-y: auto;
z-index: 101;
}

/* When main_side_bar is visible, shift actions sidebar right */
body[data-side-nav-visible='true'] #article-body .crayons-layout__sidebar-left {
left: 50px;
}

/* Main content area - compatible with main_side_bar */
#article-body #fullscreen-body {
position: fixed;
left: 60px;
top: 55px;
width: calc(100vw - 60px);
height: calc(100vh - 55px);
overflow: hidden;
transition: left 0.3s ease;
}

/* When main_side_bar is visible, shift main content right */
body[data-side-nav-visible='true'] #article-body #fullscreen-body {
left: 110px;
width: calc(100vw - 110px);
}

/* Iframe styling */
#article-body #fullscreen-body iframe {
width: 100%;
height: 100%;
border: none;
position: absolute;
top: 0;
left: 0;
/* Ensure iframe content is properly contained */
max-width: 100%;
max-height: 100%;
object-fit: contain;
}

/* Mobile responsive */
@media (max-width: 767px) {
#article-body .crayons-layout__sidebar-left {
width: 50px;
}

/* On narrow screens, make fullscreen-body truly edge-to-edge */
#article-body #fullscreen-body {
left: 0;
width: 100vw;
top: 0;
height: calc(100vh - 80px); /* Leave room for bottom actions bar */
}

/* When main_side_bar is visible on mobile */
body[data-side-nav-visible='true'] #article-body .crayons-layout__sidebar-left {
border-right: 0;
}
body[data-side-nav-visible='true'] #article-body #fullscreen-body {
left: 0px;
width: 100vw;
top: 55px;
height: calc(100vh - 113px); /* Leave room for bottom actions bar */
}
}

/* Comments modal */
.comments-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
z-index: 103;
opacity: 0;
visibility: hidden;
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.1s ease, visibility 0.1s ease;
pointer-events: none;
}

/* Responsive modal positioning for edge-to-edge layout */
@media (min-width: 768px) { /* $breakpoint-m */
body[data-side-nav-visible='true'] .comments-modal {
left: 50px;
width: calc(100vw - 50px);
}
}

@media (min-width: 1024px) { /* $breakpoint-l */
body[data-side-nav-visible='true'] .comments-modal {
left: 50px;
width: calc(100vw - 50px);
}
}

@media (min-width: 1460px) { /* $breakpoint-2xl */
body[data-side-nav-visible='true'] .comments-modal {
left: 20px;
width: calc(100vw - 20px);
}
}

.comments-modal.show {
opacity: 1;
visibility: visible;
pointer-events: auto;
}

.comments-modal-content {
background: var(--base-inverted);
border-radius: 8px;
width: 96%;
max-width: 1180px;
height: 96vh;
overflow: hidden;
position: relative;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
transform: scale(0.95);
transition: transform 0.2s ease;
}

.comments-modal.show .comments-modal-content {
transform: scale(1);
}

.comments-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 20px 10px 20px;
border-bottom: 1px solid var(--base-10);
position: sticky;
top: 0;
background: var(--base-inverted);
z-index: 1;
flex-shrink: 0;
}

.comments-modal-close {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: var(--base-60);
padding: 5px;
border-radius: 4px;
line-height: 1;
}

.comments-modal-close:hover {
background: var(--base-10);
color: var(--base-90);
}

.comments-modal-body {
padding: 0;
height: 100%;
overflow: hidden;
flex: 1;
}

/* Mobile adjustments - when sidebar isn't visible and actions are at bottom */
@media (max-width: 767px) {
.comments-modal {
align-items: flex-start; /* Align to top instead of center */
justify-content: flex-start; /* Align to left instead of center */
}

.comments-modal-content {
height: calc(100vh - 80px); /* Leave room for bottom actions bar */
margin: 0; /* Remove all margins */
border-radius: 0; /* Full edge-to-edge on mobile */
width: 100vw; /* Full viewport width */
max-width: 100vw; /* Ensure no max-width constraint */
}

.comments-modal-header {
padding: 10px 15px 8px 15px;
}

.comments-modal-body {
padding: 0;
margin: 0;
}
}

/* Custom scrollbar for sidebar */
#article-body .crayons-layout__sidebar-left::-webkit-scrollbar {
width: 4px;
}

#article-body .crayons-layout__sidebar-left::-webkit-scrollbar-track {
background: transparent;
}

#article-body .crayons-layout__sidebar-left::-webkit-scrollbar-thumb {
background: var(--base-20);
border-radius: 2px;
}

#article-body .crayons-layout__sidebar-left::-webkit-scrollbar-thumb:hover {
background: var(--base-30);
}
</style>

<div data-article-id="<%= @article.id %>" id="article-body" data-type-of="fullscreen_embed">
<aside class="crayons-layout__sidebar-left" aria-label="<%= t("views.articles.actions.aria_label") %>">
<%= render "articles/actions" %>
</aside>

<div id="fullscreen-body">
<%= @article.processed_html_final.html_safe %>
</div>
</div>

<!-- Comments modal -->
<div class="comments-modal" id="comments-modal">
<div class="comments-modal-content">
<div class="comments-modal-header">
<h2 class="crayons-subtitle-1">
Comments
<% if @comments_count > 0 %>
<span class="js-comments-count" data-comments-count="<%= @comments_count %>">
(<%= @comments_count %>)
</span>
<% end %>
</h2>
<button
class="comments-modal-close"
id="comments-modal-close"
aria-label="Close comments"
type="button">
×
</button>
</div>
<div class="comments-modal-body">
<%# Load comments in iframe to avoid encoding issues %>
<iframe
src="<%= @article.path %>/comments"
frameborder="0"
style="width: 100%; height: 100%; min-height: 400px; border: none;"
title="Article comments"
loading="lazy">
</iframe>
</div>
</div>
</div>

<script>
// Fullscreen embed functionality
document.addEventListener('DOMContentLoaded', function() {
// Only run this for fullscreen embeds
if (document.querySelector('#article-body[data-type-of="fullscreen_embed"]')) {
// Wait a bit for articleReactions.js to finish processing, then override
setTimeout(() => {
const commentsToggle = document.getElementById('reaction-butt-comment');
const commentsModal = document.getElementById('comments-modal');
const commentsModalClose = document.getElementById('comments-modal-close');

console.log('Fullscreen embed detected, modal elements found:', { commentsToggle, commentsModal, commentsModalClose });

if (commentsToggle && commentsModal && commentsModalClose) {
// Remove any existing onclick handlers to prevent conflicts
commentsToggle.onclick = null;
commentsToggle.removeAttribute('data-category');

// Add a custom attribute to prevent articleReactions.js from interfering
commentsToggle.setAttribute('data-fullscreen-embed', 'true');

// Show comments modal
commentsToggle.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
console.log('Opening comments modal');
commentsModal.classList.add('show');
document.body.style.overflow = 'hidden';
// Focus the close button for accessibility
commentsModalClose.focus();
});

// Hide comments modal
commentsModalClose.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
console.log('Closing comments modal via close button');
closeModal();
});

// Close modal when clicking outside
commentsModal.addEventListener('click', function(e) {
if (e.target === commentsModal) {
console.log('Closing comments modal via outside click');
closeModal();
}
});

// Close modal with Escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && commentsModal.classList.contains('show')) {
console.log('Closing comments modal via Escape key');
closeModal();
}
});

// Helper function to close modal
function closeModal() {
commentsModal.classList.remove('show');
document.body.style.overflow = '';
// Return focus to the toggle button
commentsToggle.focus();
console.log('Modal closed, classes:', commentsModal.className);
}
} else {
console.error('Missing modal elements:', { commentsToggle, commentsModal, commentsModalClose });
}
}, 100); // Wait for articleReactions.js to finish
}

// Ensure the fullscreen layout takes up the full viewport
const articleBody = document.getElementById('article-body');
if (articleBody) {
// Set viewport height for mobile browsers
const setViewportHeight = () => {
const vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
};
setViewportHeight();
window.addEventListener('resize', setViewportHeight);
// Handle orientation change on mobile
window.addEventListener('orientationchange', function() {
setTimeout(setViewportHeight, 100);
});

// Handle main_side_bar visibility changes
const observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.type === 'attributes' && mutation.attributeName === 'data-side-nav-visible') {
// Force reflow to ensure proper positioning
articleBody.offsetHeight;
}
});
});

observer.observe(document.body, {
attributes: true,
attributeFilter: ['data-side-nav-visible']
});
}
});
</script>

<%= javascript_include_tag "billboard", "localizeArticleDates", "articleReactions", defer: true %>
Loading
Loading