Skip to content
Closed
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Lines marked **Upgrade step** need you to act after updating.
- Each rule now shows as a sentence under its question, and a group says when it's hidden. Edit changes a rule right there, and for choices, ratings and scales you pick the answer instead of typing it. A rule whose question was deleted shows in red and can't be saved until you fix it. (#274)
- The form editor uses plain words: a question's settings are headed by its answer type, like Choices or Rating, "Identifier" is now "Short name", and every switch shows on or off. Settings name what they do, like "Lowest value", "Shuffle choices" and "None ticked: all types allowed." on file uploads. (#279)
- The editor's preview shows the end screen while you edit it, with your latest text, and says so when your form sends people to a link instead. Its button opens in a new tab there, so you stay in the editor, and typing in a question you just opened no longer goes into the preview. On a tablet or phone, Esc closes the preview even after you clicked into it. Settings now calls the Completion Page "End screen", like the editor. (#280)
- In the form editor a thin line marks where each question starts, its number stands out more, and the question you edit gets more room around it. On a phone the editor keeps a wider margin at the sides. (#281)

### Fixed

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<!-- sits in the gap below a block; it shows on hover and keyboard focus, not on touch -->
<div
class="group/add absolute -bottom-1 left-8 right-0 z-10 flex h-4 items-center justify-center sm:left-12 [@media(hover:none)]:hidden"
class="group/add absolute -bottom-2 left-8 right-0 z-10 flex h-4 items-center justify-center sm:left-12 [@media(hover:none)]:hidden"
>
<span
aria-hidden="true"
Expand Down
29 changes: 16 additions & 13 deletions resources/js/components/Factory/Document/DocumentGroup.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,26 @@
type="text"
placeholder="e.g. About you"
title="Use a group to show or hide several questions with one rule."
class="h-11 min-w-0 flex-1 rounded-md border-0 bg-transparent px-2 text-base font-semibold lg:h-9 lg:text-sm text-grey-700 placeholder:text-grey-600 hover:bg-grey-100 focus:bg-white focus:ring-2 focus:ring-blue-500"
class="h-11 min-w-40 flex-1 rounded-md border-0 bg-transparent px-2 text-base font-semibold lg:h-9 lg:text-sm text-grey-700 placeholder:text-grey-600 hover:bg-grey-100 focus:bg-white focus:ring-2 focus:ring-blue-500"
/>
<span v-if="group.is_disabled" class="text-xs text-grey-600"
>Always hidden</span
>
<button
type="button"
class="flex h-11 items-center rounded-md px-2 text-sm font-semibold text-blue-700 lg:h-9 hover:bg-blue-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500"
@click="addRule(group)"
>
Add rule
</button>
<BlockMenu
:block="group"
:label="`Options for group ${group.title || 'Group'}`"
@add-to-group="addQuestion"
/>
<!-- one unit, so on a phone both wrap below the name, on the right -->
<div class="ml-auto flex items-center gap-2">
<button
type="button"
class="flex h-11 items-center rounded-md px-2 text-sm font-semibold text-blue-700 lg:h-9 hover:bg-blue-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500"
@click="addRule(group)"
>
Add rule
</button>
<BlockMenu
:block="group"
:label="`Options for group ${group.title || 'Group'}`"
@add-to-group="addQuestion"
/>
</div>
</div>
<BlockRules :block="group" :numbers="numbers" class="pb-2 pl-8" />

Expand Down
45 changes: 45 additions & 0 deletions resources/js/components/Factory/Document/DocumentList.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,48 @@ describe("adding a question inside the document", () => {
);
});
});

describe("lines and air between blocks", () => {
const group = { id: 4, uuid: "g1", type: "group" } as FormBlockModel;

// the box around each block, in document order
const items = (list: FormBlockModel[]) => {
useForm().blocks = list;
wrapper = mount(DocumentList, {
props: { numbers: { b1: 1, b2: 2, b3: 3 } },
global: { stubs: { QuestionCard: true, DocumentGroup: true } },
});
return wrapper.findAll(".smooth-dnd-draggable-wrapper > div.relative");
};

beforeEach(() => {
useForm().$reset();
useWorkbench().$reset();
});

afterEach(() => wrapper?.unmount());

it("draws a line at the start of each question but the first, not next to a group", () => {
const lines = items([blocks[0], group, blocks[1], blocks[2]]).map(
(item) => item.classes("border-t"),
);

expect(lines).toEqual([false, false, false, true]);
});

it("gives the open question 24 px above and below, the others 8 px", () => {
useWorkbench().block = blocks[1];

const padding = items(blocks).map((item) =>
["py-2", "py-6"].filter((name) => item.classes(name)),
);

expect(padding).toEqual([["py-2"], ["py-6"], ["py-2"]]);
});

it("keeps an open group at 8 px, so its frame doesn't move", () => {
useWorkbench().block = group;

expect(items([blocks[0], group])[1].classes()).toContain("py-2");
});
});
21 changes: 19 additions & 2 deletions resources/js/components/Factory/Document/DocumentList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
@drop="onDrop"
>
<Draggable v-for="(block, index) in blocks" :key="block.uuid">
<div class="relative pb-2">
<div class="relative" :class="itemClass(block, index)">
<DocumentGroup
v-if="block.type === 'group'"
:group="block"
Expand Down Expand Up @@ -48,7 +48,7 @@
<script setup lang="ts">
import { computed } from "vue";
import { Container, Draggable } from "vue3-smooth-dnd";
import { useForm } from "@/stores";
import { useForm, useWorkbench } from "@/stores";
import DocumentGroup from "./DocumentGroup.vue";
import DocumentQuestion from "./DocumentQuestion.vue";
import AddQuestionLine from "./AddQuestionLine.vue";
Expand All @@ -62,6 +62,7 @@ const props = defineProps<{
}>();

const store = useForm();
const workbench = useWorkbench();
const { addQuestion } = useAddQuestion();

const blocks = computed(() =>
Expand All @@ -70,6 +71,22 @@ const blocks = computed(() =>
),
);

// a line where each question starts, but not against a group's own frame;
// the open question gets 24 px of air, an open group stays put
const itemClass = (block: FormBlockModel, index: number) => {
const before = blocks.value[index - 1];

return [
block.type !== "group" && workbench.block?.id === block.id
? "py-6"
: "py-2",
before &&
block.type !== "group" &&
before.type !== "group" &&
"border-t border-grey-200",
];
};

const getChildPayload = (index: number) => blocks.value[index];

const shouldAcceptDrop = (source: any, payload?: FormBlockModel) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<div class="flex w-8 shrink-0 flex-col sm:w-12 items-end gap-1 pr-2 pt-3">
<span
aria-hidden="true"
class="flex h-6 items-center text-[13px] tabular-nums text-grey-600"
class="flex h-6 items-center text-sm font-semibold tabular-nums text-grey-700"
><span
:class="
isJumpTarget &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,14 @@ describe("the end screen in the document", () => {
expect(endScreenOpen.value).toBe(false);
});

it("gets 24 px above and below when open, like an open question", async () => {
expect(mountBlock().get("#row-end-screen").classes()).toContain("pt-2");

const row = (await open()).get("#row-end-screen");
expect(row.classes()).toContain("py-6");
expect(row.classes()).not.toContain("pt-2");
});

it("has the question card's phone sizes, number column and focus bar", async () => {
const block = await open();
const [number, card] = block.findAll("#row-end-screen > div");
Expand Down
8 changes: 6 additions & 2 deletions resources/js/components/Factory/Document/EndScreenBlock.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<template>
<div id="row-end-screen" class="relative flex items-start">
<div
id="row-end-screen"
class="relative flex items-start"
:class="isOpen ? 'py-6' : 'pt-2'"
>
<div class="flex w-8 shrink-0 justify-end pr-2 pt-3 sm:w-12">
<span class="flex h-6 items-center text-grey-500">
<D9Icon name="flag" aria-hidden="true" />
Expand All @@ -22,7 +26,7 @@

<div
v-else-if="isOpen"
class="touch-fields min-w-0 flex-1 space-y-4 rounded-lg bg-white p-3 shadow-sm ring-1 ring-blue-500 sm:p-4"
class="touch-fields min-w-0 flex-1 space-y-4 rounded-lg bg-white p-3 shadow-md ring-1 ring-blue-500 sm:p-4"
@focusout="leave"
>
<div class="flex items-center gap-3">
Expand Down
26 changes: 26 additions & 0 deletions resources/js/components/Factory/Document/FormDocument.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,30 @@ describe("the form document", () => {
expect(text.indexOf(first)).toBeGreaterThan(-1);
expect(text.indexOf("[end]")).toBeGreaterThan(text.indexOf(first));
});

it("starts the end screen with a line, but not against a group's frame", () => {
const group = { id: 3, uuid: "g1", type: "group" } as FormBlockModel;
const inGroup = {
id: 4,
uuid: "b4",
type: "none",
parent_block: "g1",
} as FormBlockModel;
const line = (list: FormBlockModel[]) => {
wrapper?.unmount();
useForm().blocks = list;
wrapper = mount(FormDocument, {
props: { status: "loaded" },
global: { stubs },
});
return wrapper
.findAll("div")
.find((item) => item.text() === "[end]")!
.classes("border-t");
};

expect(line(blocks)).toBe(true);
expect(line([...blocks, group, inGroup])).toBe(false);
expect(line([])).toBe(false);
});
});
11 changes: 9 additions & 2 deletions resources/js/components/Factory/Document/FormDocument.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
class="h-full min-w-0 flex-1 overflow-y-auto bg-white"
>
<div
class="mx-auto w-full max-w-[720px] px-2 pb-40 pt-6 sm:px-6 sm:pt-10"
class="mx-auto w-full max-w-[720px] px-4 pb-40 pt-6 sm:px-6 sm:pt-10"
>
<div v-if="status !== 'loaded'" class="pl-12">
<QuestionsLoadState :status="status" @retry="retry" />
Expand Down Expand Up @@ -61,7 +61,7 @@
@pick="addQuestion"
/>

<EndScreenBlock class="mt-2" />
<EndScreenBlock :class="endLine && 'border-t border-grey-200'" />

<div
id="add-buttons"
Expand Down Expand Up @@ -220,6 +220,13 @@ const pick = async (block: FormBlockModel) => {

const numbers = computed(() => questionNumbers(store.blocks ?? []));

// the end screen starts with a line like a question, but not against a group's frame
const endLine = computed(() => {
const top = (store.blocks ?? []).filter((block) => !block.parent_block);

return top.length > 0 && top[top.length - 1].type !== "group";
});

const countLine = computed(() => {
const questions = Object.keys(numbers.value).length;
const groups = (store.blocks ?? []).filter(
Expand Down
2 changes: 1 addition & 1 deletion resources/js/components/Factory/Document/QuestionCard.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div
class="touch-fields min-w-0 flex-1 space-y-4 rounded-lg bg-white p-3 shadow-sm ring-1 ring-blue-500 sm:p-4"
class="touch-fields min-w-0 flex-1 space-y-4 rounded-lg bg-white p-3 shadow-md ring-1 ring-blue-500 sm:p-4"
>
<span :id="`${id}-text-label`" class="sr-only"
>Question {{ number }} text</span
Expand Down