inject fullscreen toggle button directly into preview pane iframe

Hunter
Wednesday, July 16th, 2025 at 3:53 PM

index.html+73-63

index.html
 50  			position: relative;
 51  		}
 52  
    -		.fullscreen-toggle {
    -			position: absolute;
    -			top: 5px;
    -			right: 5px;
    -			z-index: 10000;
    -			background: rgba(0, 0, 0, 0.2);
    -			color: white;
    -			border: none;
    -			border-radius: 4px;
    -			width: 32px;
    -			height: 32px;
    -			display: flex;
    -			align-items: center;
    -			justify-content: center;
    -			cursor: pointer;
    -			transition: background-color 0.2s;
    -			box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
    -		}
    -
    -		.fullscreen-toggle.has-scrollbar {
    -			right: calc(5px + env(scrollbar-width, 15px));
    -		}
    -
    -		@media (pointer: none), (pointer: coarse) {
    -			.fullscreen-toggle.has-scrollbar {
    -				right: 5px;
    -			}
    -		}
    -
    -		.fullscreen-toggle:hover {
    -			background: rgba(0, 0, 0, 0.35);
    -		}
    -
    -		.fullscreen-toggle img {
    -			filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.3));
    -			opacity: 0.8;
    -			transition: opacity 0.2s;
    -		}
    -
    -		.fullscreen-toggle:hover img {
    -			opacity: 1;
    -		}
    -
 53  		.preview-pane.fullscreen {
 54  			position: fixed;
 55  			top: 0;

146  	</div>
147  	
148  	<div class="preview-pane">
    -		<button class="fullscreen-toggle" id="fullscreenToggle" title="Toggle fullscreen">
    -			<img src="resources/fullscreen.svg" width="20" height="20" alt="Fullscreen">
    -		</button>
149  		<iframe id="preview"></iframe>
150  	</div>
151  

159  		function toggleFullscreen() {
160  			const previewPane = document.querySelector('.preview-pane');
161  			const editorPane = document.querySelector('.editor-pane');
    -			const toggleButton = document.getElementById('fullscreenToggle');
162  			
163  			isFullscreen = !isFullscreen;
164  			
165  			if (isFullscreen) {
166  				previewPane.classList.add('fullscreen');
167  				editorPane.classList.add('hidden');
    -				toggleButton.title = 'Exit fullscreen';
168  			} else {
169  				previewPane.classList.remove('fullscreen');
170  				editorPane.classList.remove('hidden');
    -				toggleButton.title = 'Toggle fullscreen';
171 +			}
172 +			
173 +			// Update button title in iframe
174 +			try {
175 +				const toggleButton = preview.contentDocument.getElementById('fullscreenToggle');
176 +				if (toggleButton) {
177 +					toggleButton.title = isFullscreen ? 'Exit fullscreen' : 'Toggle fullscreen';
178 +				}
179 +			} catch (e) {
180 +				// Ignore cross-origin errors
181  			}
182  		}
183  
    -		document.addEventListener('DOMContentLoaded', function() {
    -			const toggleButton = document.getElementById('fullscreenToggle');
    -			toggleButton.addEventListener('click', toggleFullscreen);
    -		});
184  
    -		function updateScrollbarDetection() {
    -			const toggleButton = document.getElementById('fullscreenToggle');
185 +		function createFullscreenToggle() {
186  			try {
    -				if (preview.contentDocument && preview.contentDocument.body) {
    -					const body = preview.contentDocument.body;
    -					const hasScrollbar = body.scrollHeight > preview.clientHeight;
    -					toggleButton.classList.toggle('has-scrollbar', hasScrollbar);
187 +				if (!preview.contentDocument) return;
188 +				
189 +				const doc = preview.contentDocument;
190 +				
191 +				// Remove existing button if it exists
192 +				const existingButton = doc.getElementById('fullscreenToggle');
193 +				if (existingButton) {
194 +					existingButton.remove();
195 +				}
196 +				
197 +				// Create button element
198 +				const button = doc.createElement('button');
199 +				button.id = 'fullscreenToggle';
200 +				button.className = 'iframe-fullscreen-toggle';
201 +				button.title = 'Toggle fullscreen';
202 +				button.innerHTML = `<img src="resources/fullscreen.svg" width="20" height="20" alt="Fullscreen">`;
203 +				
204 +				// Add click handler
205 +				button.addEventListener('click', toggleFullscreen);
206 +				
207 +				// Append to body
208 +				if (doc.body) {
209 +					doc.body.appendChild(button);
210  				}
211  			} catch (e) {
212  				// Ignore cross-origin errors

232  			doc.open();
233  			doc.write(code);
234  			
    -			// Inject CSS to disable overscroll in iframe content
235 +			// Inject CSS to disable overscroll and add fullscreen toggle styles
236  			const style = doc.createElement('style');
    -			style.textContent = `* { overscroll-behavior: none !important; }`;
237 +			style.textContent = `
238 +				* { overscroll-behavior: none !important; }
239 +				
240 +				.iframe-fullscreen-toggle {
241 +					position: fixed;
242 +					top: 5px;
243 +					right: 5px;
244 +					z-index: 10000;
245 +					background: rgba(0, 0, 0, 0.2);
246 +					color: white;
247 +					border: none;
248 +					border-radius: 4px;
249 +					width: 32px;
250 +					height: 32px;
251 +					display: flex;
252 +					align-items: center;
253 +					justify-content: center;
254 +					cursor: pointer;
255 +					transition: background-color 0.2s;
256 +					box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
257 +				}
258 +
259 +				.iframe-fullscreen-toggle:hover {
260 +					background: rgba(0, 0, 0, 0.35);
261 +				}
262 +
263 +				.iframe-fullscreen-toggle img {
264 +					filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.3));
265 +					opacity: 0.8;
266 +					transition: opacity 0.2s;
267 +				}
268 +
269 +				.iframe-fullscreen-toggle:hover img {
270 +					opacity: 1;
271 +				}
272 +			`;
273  			if (doc.head) {
274  				doc.head.appendChild(style);
275  			}

285  				} catch (e) {
286  					// Ignore cross-origin errors
287  				}
    -				// Check for scrollbar after content is rendered
    -				updateScrollbarDetection();
288 +				// Create fullscreen toggle button after content is rendered
289 +				createFullscreenToggle();
290  			}, 10);
291  		}
292