inject fullscreen toggle button directly into preview pane iframe
Hunter
Wednesday, July 16th, 2025 at 3:53 PM
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