Repository navigation
feat: show a live preview beside the document - #273
PhilReinking wants to merge 22 commits into
Conversation
Preview in the top bar shows the public form in preview mode: beside the document on a desktop, as a panel over it on tablet and phone. It follows the open question, and the document follows Next and Back in the preview. A saved change reloads it at the open question. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The preview shows a small note instead of the owner's orange bar, also on a copied preview link. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The phone's top bar keeps its room for the form name, as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The phone form menu and the bar's default Preview link opened the real form, so answers given there were stored. Both now add ?preview=1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A mouse click on the button's text landed on an inner span. On close the dialog tried to focus that span, which can't take focus, so focus fell to the page. The button's inside now lets clicks through to the button. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The button is 32 px high. An invisible edge 6 px above and below makes the tap area 44 px without changing its look. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shrinking the window below 1280 px, or turning a tablet to portrait, opened the preview as a panel over the document and moved focus into it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A form without questions showed a blank white frame, which looked broken. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… open one The heading reads "Preview · question 3". When the open question is hidden by a rule, the preview stays where it is; a grey line now says why. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to feat/bits-285-preview-panel Conflict in the document's count row: part b's Outline button and the preview's actions slot now sit side by side. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With both buttons the row needs about 376 px but has 296 px at 360. Below sm both are now 44 px icon buttons, their labels come back from sm, and Preview looks like Outline beside it. Clicks land on the buttons, so focus can go back to them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In the editor, the form menu's Preview now opens the preview panel at the open question, as the Preview button does. That button scrolls away on a long form; the menu stays in reach. Other pages keep the new tab in preview mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PhilReinking
left a comment
There was a problem hiding this comment.
Changes at cbfd30d. No CI (stacked), local runs: Vitest 314, lint, vue-tsc, build, PHP suite on MariaDB 743 passed (one known flaky storyboard test failed).
One must, two shoulds inline. Held: the new tests fail on the base, messages pass only between the editor and its own frame, a full preview run (draft and live, with a file) stores nothing, steady typing reloads once, and Esc and Close return focus to Preview.
| // every save that works clears its error; rules save on their own | ||
| useNotice().$onAction(({ name, after }) => { | ||
| if (name === "clearSaveError") after(reload); | ||
| }); |
There was a problem hiding this comment.
Deleting a question, a choice or a rule doesn't reload the preview. The stores call clearSaveError before they remove the item, so reload still sees the old list and stops. In a live run the preview kept a deleted choice until the next edit. Checking one tick later fixes it, and the reload test then needs one more await nextTick():
| // every save that works clears its error; rules save on their own | |
| useNotice().$onAction(({ name, after }) => { | |
| if (name === "clearSaveError") after(reload); | |
| }); | |
| // every save that works clears its error, then the store takes in the answer | |
| // (a deleted question leaves the list only after that); rules save on their own | |
| useNotice().$onAction(({ name, after }) => { | |
| if (name === "clearSaveError") after(() => nextTick(reload)); | |
| }); |
| return; | ||
| } | ||
|
|
||
| loaded = content(); |
There was a problem hiding this comment.
When two saves overlap, the preview misses the second one. Example: edit the question, then a choice within a second. The question's save reloads the preview and counts the unsaved choice as shown, so the choice's save reloads nothing. In a live run the server had the new choice "Green" and the preview kept "Red" until the next edit. Maybe count an edit as shown only once its own save is back.
| import { useMediaQuery } from "@vueuse/core"; | ||
| import PreviewFrame from "./PreviewFrame.vue"; | ||
|
|
||
| const open = defineModel<boolean>({ required: true }); | ||
|
|
||
| const isWide = useMediaQuery("(min-width: 1280px)"); |
There was a problem hiding this comment.
On a desktop the preview is on, so a window that gets narrower than 1280 px opens the panel over the document and moves the focus into it. I would close it when the window gets narrower:
| import { useMediaQuery } from "@vueuse/core"; | |
| import PreviewFrame from "./PreviewFrame.vue"; | |
| const open = defineModel<boolean>({ required: true }); | |
| const isWide = useMediaQuery("(min-width: 1280px)"); | |
| import { useMediaQuery } from "@vueuse/core"; | |
| import { watch } from "vue"; | |
| import PreviewFrame from "./PreviewFrame.vue"; | |
| const open = defineModel<boolean>({ required: true }); | |
| const isWide = useMediaQuery("(min-width: 1280px)"); | |
| // a window that gets narrower keeps the document: the panel opens only on a click | |
| watch(isWide, (wide) => { | |
| if (!wide) open.value = false; | |
| }); |
The stores clear the save error before they take the item out, so the reload still saw the old list and kept the preview. It now waits a tick. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A save that came back first reloaded the preview and counted a change that was still waiting to save as shown, so that change's own save reloaded nothing. Now each save that carries a change reloads once it is back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The questions load after the panel, so the first preview had no question to start at, began at question 1 and then jumped. It now waits for the open question. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The panel opened while the menu was still closing, so it remembered the gone menu item and the name inside the menu button, and closing it left focus on the page. It now opens once the menu gave focus back to its button. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…to feat/bits-285-preview-panel # Conflicts: # resources/js/Pages/Forms/Edit.vue
…to feat/bits-285-preview-panel # Conflicts: # resources/js/components/Factory/Document/FormDocument.test.ts
PhilReinking
left a comment
There was a problem hiding this comment.
OK at 12ed786 (re-check of cbfd30d..12ed786). No CI (stacked), local runs: Vitest 386, lint, vue-tsc, build.
The must and both shoulds are fixed: a deleted question, choice or rule reloads the preview, two overlapping saves both show, and a narrower window closes the panel. The 15 new tests fail on the old code. Two new shoulds inline. Held: the merge keeps parts b and c, and the message checks are unchanged.
| // the questions load after the panel: start at the open one, not at the | ||
| // first and then jump | ||
| const src = ref<string>(); | ||
| watch( | ||
| () => workbench.block, | ||
| (block) => { | ||
| if (block) src.value ??= url(); | ||
| }, | ||
| { immediate: true }, | ||
| ); |
There was a problem hiding this comment.
Should: a panel that opens while no question is open stays blank, with only "Preview" in it. On a phone: delete the open question, then tap Preview. On a desktop: Escape in a question, then Preview off and on. Starting at once when the questions are already loaded fixes it. The "waits for the questions" test then mounts with blocks = null (I ran it: 18 of 18 pass).
| // the questions load after the panel: start at the open one, not at the | |
| // first and then jump | |
| const src = ref<string>(); | |
| watch( | |
| () => workbench.block, | |
| (block) => { | |
| if (block) src.value ??= url(); | |
| }, | |
| { immediate: true }, | |
| ); | |
| // the questions load after the panel: start at the open one, not at the | |
| // first and then jump; a panel opened later with none open starts at once | |
| const src = ref(store.blocks ? url() : undefined); | |
| watch( | |
| () => workbench.block, | |
| (block) => { | |
| if (block) src.value ??= url(); | |
| }, | |
| ); |
| <p v-if="hiddenNumber" class="w-80 max-w-full text-xs text-grey-600"> | ||
| Question {{ hiddenNumber }} is hidden by a rule, so the preview can't jump | ||
| to it. | ||
| </p> |
There was a problem hiding this comment.
Should: the server leaves a Hidden question (and every question in a Hidden group) out of the public form. Opening one says "hidden by a rule", so the owner looks for a rule that isn't there. Maybe "Question {{ hiddenNumber }} is hidden or skipped by a rule, so the preview can't show it." The panel below has the same text. Not run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A hidden question, or one in a hidden group, is left out of the public form; the note blamed a rule for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PhilReinking
left a comment
There was a problem hiding this comment.
OK at a1f2a83. No CI (stacked), local runs: Vitest 389, lint, vue-tsc, build.
Both shoulds are fixed, and the 3 new tests fail on 12ed786. On a phone, deleting the open question and then tapping Preview runs the form at question 1. The note names the right reason for a hidden question, a question in a hidden group and one hidden by a rule. A full preview run stored nothing.
|
Landed in main with #282 (the editor rebuild as one PR); this PR's commits are part of it. |
"Preview" in the editor shows the form in preview mode: beside the document on a desktop, as a panel on tablet and phone. It follows the open question, and Next in the preview opens that question in the document.
Fixes BITS-285
sm. The form menu's Preview opens the panel; other pages open?preview=1in a new tab.Tested: Vitest, lint, vue-tsc, build (stacked, no CI); by hand at 1440, 1024, 390 on a draft and a live form, nothing stored. New tests fail without the change.
Not tested: Safari and Firefox.
Screenshots: on BITS-285.
🤖 Generated with Claude Code