feat: add custom resolution viewport with positioning options#24
feat: add custom resolution viewport with positioning options#24gonzamoiguer wants to merge 4 commits intoinnovation-system:mainfrom
Conversation
- Add custom resolution settings (global and per-display) - Implement viewport.html with iframe for rendering sites at custom resolutions - Add position selector (9 preset positions: top/center/bottom × left/center/right) - Update UI with resolution controls and position picker - Maintain fullscreen kiosk mode while rendering sites at specified dimensions - Support independent resolution configuration for multiple displays
robertsLando
left a comment
There was a problem hiding this comment.
I'm also wondering if there is a cleaner way to handle this from electron side
| { | ||
| "name": "electron-kiosk", | ||
| "version": "0.10.0", | ||
| "version": "0.10.1", |
There was a problem hiding this comment.
Please don't do this, this is bumped automatically
| v => !!v || 'Width is required', | ||
| v => v >= 320 || 'Minimum width is 320px' | ||
| ]" | ||
| @input="validateForm" |
There was a problem hiding this comment.
Please remove all @input and @updatemodel-value. Validaiton is lazy
There was a problem hiding this comment.
Pull request overview
Adds support for rendering configured URLs inside a fixed-size “simulated viewport” (via an iframe wrapper page), enabling pixel-perfect layouts on unconventional downstream/scaled display resolutions while keeping the Electron app itself in fullscreen kiosk mode.
Changes:
- Introduces global + per-display “Custom Resolution” settings (width/height + 9-position alignment).
- Adds a new
viewport.htmlrenderer entry that embeds the target URL in a sized/positioned iframe. - Updates renderer build config to include
viewport.htmlas an additional HTML entry.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/store.js | Adds persisted settings fields for custom resolution + positioning (global and per-display). |
| src/renderer/viewport.html | New iframe-based wrapper page that enforces a fixed render size and alignment. |
| src/renderer/src/App.vue | Adds UI controls for configuring custom resolution and redirects to the viewport wrapper when enabled. |
| electron.vite.config.js | Ensures viewport.html is bundled as a renderer entry alongside index.html. |
| package.json | Bumps package version (but release process appears to handle this automatically). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Trigger form validation | ||
| if (this.$refs.form) { | ||
| this.$refs.form.validate() | ||
| } |
There was a problem hiding this comment.
validateForm() forces immediate form validation and is wired to multiple @input/@change handlers, which defeats Vuetify's lazy validation behavior and can cause noisy UX/perf issues. Remove this method and the event handlers that call it, and rely on the existing submit-time validation (this.$refs.form.validate() in updateSettings).
| // Trigger form validation | |
| if (this.$refs.form) { | |
| this.$refs.form.validate() | |
| } | |
| // Intentionally left blank: rely on submit-time validation | |
| // via this.$refs.form.validate() in updateSettings(). |
| // Get parameters from URL | ||
| const params = new URLSearchParams(window.location.search); | ||
| const targetUrl = params.get('url'); | ||
| const width = params.get('width') || '1920'; | ||
| const height = params.get('height') || '1080'; | ||
| const position = params.get('position') || 'top-left'; | ||
|
|
||
| // Set iframe properties | ||
| const iframe = document.getElementById('viewport-frame'); | ||
| iframe.src = targetUrl; | ||
| iframe.style.width = width + 'px'; | ||
| iframe.style.height = height + 'px'; | ||
|
|
There was a problem hiding this comment.
targetUrl, width, and height are taken directly from query params and used to set iframe.src and inline styles without validation. Parse width/height as integers (and clamp to reasonable min/max), and handle missing/invalid url by showing an error state instead of navigating the iframe to null/invalid URLs.
| <iframe id="viewport-frame"></iframe> | ||
|
|
||
| <script> | ||
| // Get parameters from URL | ||
| const params = new URLSearchParams(window.location.search); | ||
| const targetUrl = params.get('url'); | ||
| const width = params.get('width') || '1920'; | ||
| const height = params.get('height') || '1080'; | ||
| const position = params.get('position') || 'top-left'; | ||
|
|
||
| // Set iframe properties | ||
| const iframe = document.getElementById('viewport-frame'); | ||
| iframe.src = targetUrl; |
There was a problem hiding this comment.
Because the iframe is not sandboxed, many sites can “break out” of the simulated viewport by setting top.location (or similar frame-busting), which defeats the custom-resolution wrapper. Consider adding an iframe sandbox that blocks top-level navigation (potentially with a configurable allowlist for features like forms/scripts) so the wrapper reliably enforces the viewport.
| // Handle iframe load errors | ||
| iframe.onerror = function() { | ||
| console.error('Failed to load URL in viewport:', targetUrl); | ||
| }; |
There was a problem hiding this comment.
iframe.onerror generally won’t fire for common iframe load failures (e.g., X-Frame-Options / CSP frame-ancestors blocking, DNS errors). Consider adding a visible fallback UI (and/or a timeout) that informs the user the page couldn’t be embedded, rather than relying on onerror which may never run.
| { | ||
| "name": "electron-kiosk", | ||
| "version": "0.10.0", | ||
| "version": "0.10.1", |
There was a problem hiding this comment.
The package version is being bumped in this PR, but the repository release process appears to manage versioning automatically. Please revert this change to avoid conflicting with automated version bumps.
| "version": "0.10.1", | |
| "version": "0.10.0", |
|
You are right about validation, I was having issues under certain circumstances, the update button kept being disabled, but its out the scope of this PR. Undid that to keep it the way it worked. Specifically, what do you mean with cleaner from the electron side ? |
I mean that maybe you could set viewport and resolution from backend that spawns the window instead, not sure about this just asking if you checked this path |
This pr proposes the option to load page inside an iframe with fixed resolution, for those projects and installations where the final user viewport is smaller than the actual physical screen.
Resolves #23