Skip to content
Merged
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
127 changes: 127 additions & 0 deletions assets/css/builder.css
Original file line number Diff line number Diff line change
Expand Up @@ -2942,3 +2942,130 @@ os-checkbox-label.atfb-check {
font-style: italic;
color: var( --atfb-muted );
}

/* -------------------------------------------------------------------------- */
/* The repeater as a container on the canvas */
/* -------------------------------------------------------------------------- */

/* The frame borrows the front end's own row-card classes for its border and
background, so the builder shows the card the visitor will get; everything
prefixed atfb- is builder chrome on top of it. */

.atfb-repeater {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 18px;
margin-block-start: 8px;
}

.atfb-repeater__frame {
inline-size: 100%;
}

.atfb-repeater__title {
display: inline-flex;
gap: 5px;
align-items: baseline;
}

.atfb-repeater__item-label {
min-inline-size: 3ch;
}

.atfb-repeater__ordinal {
opacity: 0.55;
}

/* The zone is where sub-fields live and where drags land. Padded even when
empty so there is always something to aim a drop at. */
.atfb-repeater__zone {
display: flex;
flex-direction: column;
gap: 10px;
padding: 14px;
min-block-size: 56px;
border-radius: 0 0 var( --atf-radius-field, 8px ) var( --atf-radius-field, 8px );
}

.atfb-repeater__zone.is-dropping {
background: var( --atfb-accent-soft );
box-shadow: inset 0 0 0 2px var( --atfb-accent-line );
}

.atfb-repeater__empty {
margin: 0;
padding: 14px;
border: 1px dashed var( --atfb-border-strong );
border-radius: var( --atfb-radius );
font-size: 12px;
color: var( --atfb-muted );
text-align: center;
}

/* One sub-field: a smaller card with its own head, selection ring and grab
cursor, holding a full live preview of the control. */
.atfb-subcard {
border: 1px solid var( --atfb-border );
border-radius: var( --atfb-radius );
background: var( --atfb-bg );
cursor: grab;
touch-action: none;
}

.atfb-subcard:hover {
border-color: var( --atfb-accent );
}

.atfb-subcard.is-selected {
border-color: var( --atfb-accent );
box-shadow: 0 0 0 2px var( --atfb-accent-soft );
}

.atfb-subcard:focus-visible {
outline: 2px solid var( --atfb-accent );
outline-offset: 2px;
}

.atfb-subcard__head {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 10px;
border-block-end: 1px solid var( --atfb-border );
}

.atfb-subcard__type {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.02em;
color: var( --atfb-muted );
}

.atfb-subcard__required {
font-size: 11px;
color: var( --atfb-warning );
}

.atfb-subcard__head .atfb-preview__remove {
margin-inline-start: auto;
opacity: 1;
}

.atfb-subcard .atfb-preview {
padding: 10px 12px;
}

/* The editable Add-another button sits under the frame with the same breathing
room the front end gives it. */
.atfb-repeater > .atfb-repeater__add {
margin-block-start: 0;
}

/* The crumb that says a field lives inside a repeater. */
.atfb-inspector__crumb {
padding: 6px 8px;
border-radius: 4px;
background: var( --atfb-well );
}
52 changes: 42 additions & 10 deletions assets/css/form.css
Original file line number Diff line number Diff line change
Expand Up @@ -912,22 +912,41 @@

.atf-repeater__rows {
display: grid;
gap: 12px;
gap: 14px;
margin-block-start: var( --atf-gap-label );
}

/* Each row is a card: a named thing — "Attendee 1" — rather than an anonymous
stripe of boxes, because the whole point of a repeater is that one row is one
*thing* the visitor is describing. */
.atf-repeater__row {
position: relative;
display: grid;
grid-template-columns: repeat( 12, 1fr );
gap: 12px;
padding: 14px;
padding-inline-end: 44px;
border: var( --atf-border-width ) var( --atf-border-style ) var( --atf-border );
border-radius: var( --atf-radius-field );
background: var( --atf-surface-alt );
}

.atf-repeater__row-head {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 10px 16px;
border-block-end: var( --atf-border-width ) var( --atf-border-style ) var( --atf-border );
}

.atf-repeater__title {
font-size: var( --atf-size-label );
font-weight: var( --atf-weight-label );
color: var( --atf-heading );
}

.atf-repeater__row-grid {
display: grid;
grid-template-columns: repeat( 12, 1fr );
gap: 14px;
padding: 16px;
}

.atf-repeater__field {
grid-column: span 12;
}
Expand All @@ -940,12 +959,17 @@
grid-column: span 4;
}

@container atf-form ( max-width: 480px ) {
.atf-repeater__field.atf-field--half,
.atf-repeater__field.atf-field--third {
grid-column: span 12;
}
}

.atf-repeater__remove {
position: absolute;
inset-block-start: 8px;
inset-inline-end: 8px;
inline-size: 28px;
block-size: 28px;
flex: none;
display: grid;
place-items: center;
border: 0;
Expand All @@ -962,6 +986,14 @@
color: var( --atf-error );
}

/* Breathing room the button was missing: it sits under the row cards, not
glued to them, and never stretches to the form's full width — themes whose
`--atf-button-width` is 100% mean the submit button, not this one. */
.atf-repeater__add {
margin-block-start: 18px;
inline-size: auto;
}

/* -------------------------------------------------------------------------- */
/* Layout fields */
/* -------------------------------------------------------------------------- */
Expand Down
6 changes: 4 additions & 2 deletions assets/js/analytics.js
Original file line number Diff line number Diff line change
Expand Up @@ -722,7 +722,9 @@ var allTerrainFormsAnalytics = function(exports) {
parts.push(
el("p", {
class: "atfa-question__note",
text: `${field.answered} of ${sampled} people answered this.`
// A repeater sub-field is answered per row, not per
// person, and says so through `of` and `unit`.
text: `${field.answered} of ${field.of ?? sampled} ${field.unit ?? "people"} answered this.`
})
);
}
Expand All @@ -734,7 +736,7 @@ var allTerrainFormsAnalytics = function(exports) {
if (field.numbers) {
bits.push(`mean ${field.numbers.mean}`, `median ${field.numbers.median}`);
}
bits.push(`${field.answered}/${sampled}`);
bits.push(`${field.answered}/${field.of ?? sampled}`);
return bits.join(" · ");
}
/**
Expand Down
Loading
Loading