Design language tweaks v3
This commit is contained in:
@@ -0,0 +1,694 @@
|
||||
<script lang="ts">
|
||||
export let idPrefix: string;
|
||||
export let lead = '';
|
||||
export let submitLabel = 'Book a free Meet & Greet';
|
||||
export let tone: 'default' | 'conversational' | 'minimal' = 'default';
|
||||
export let layout: 'stacked' | 'carded' = 'stacked';
|
||||
export let eyebrow = 'Free Meet & Greet';
|
||||
export let title = 'Tell us about your dog';
|
||||
export let subtitle =
|
||||
'A guided first step so we can recommend the right walk, visit, or calmer starting point.';
|
||||
|
||||
let submitted = false;
|
||||
let step = 1;
|
||||
let ownerStepUnlocked = false;
|
||||
|
||||
function handleSubmit() {
|
||||
if (step === 1) {
|
||||
ownerStepUnlocked = true;
|
||||
step = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
submitted = true;
|
||||
}
|
||||
|
||||
function goToStep(nextStep: number) {
|
||||
if (nextStep === 2 && !ownerStepUnlocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
step = nextStep;
|
||||
}
|
||||
</script>
|
||||
|
||||
<form
|
||||
class={`vf-form vf-form--${tone} vf-form--${layout}`}
|
||||
on:submit|preventDefault={handleSubmit}
|
||||
novalidate
|
||||
>
|
||||
<div class="vf-header">
|
||||
<span class="vf-eyebrow">{eyebrow}</span>
|
||||
<h3 class="vf-title">{title}</h3>
|
||||
<p class="vf-subtitle">{subtitle}</p>
|
||||
|
||||
<div class="vf-stepper" aria-label="Application steps">
|
||||
<button
|
||||
type="button"
|
||||
class:active={step === 1}
|
||||
class="vf-step"
|
||||
on:click={() => goToStep(1)}
|
||||
>
|
||||
<span class="vf-step-number">1</span>
|
||||
<span class="vf-step-label">Dog details</span>
|
||||
</button>
|
||||
<span class="vf-step-divider" aria-hidden="true"></span>
|
||||
<button
|
||||
type="button"
|
||||
class:active={step === 2}
|
||||
class="vf-step"
|
||||
disabled={!ownerStepUnlocked}
|
||||
aria-disabled={!ownerStepUnlocked}
|
||||
on:click={() => goToStep(2)}
|
||||
>
|
||||
<span class="vf-step-number">2</span>
|
||||
<span class="vf-step-label">Owner details</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if lead}
|
||||
<p class="vf-lead">{lead}</p>
|
||||
{/if}
|
||||
|
||||
{#if step === 1}
|
||||
<section class="vf-group" aria-labelledby={`${idPrefix}-dog-group`}>
|
||||
<div class="vf-group-head">
|
||||
<p class="vf-kicker" id={`${idPrefix}-dog-group`}>Dog details</p>
|
||||
<p class="vf-group-copy">
|
||||
A few calm details first so we can judge fit, pace, and the right kind of outing.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="vf-grid vf-grid--two">
|
||||
<label class="vf-field">
|
||||
<span class="vf-label">Dog name</span>
|
||||
<input id={`${idPrefix}-dog-name`} name="dogName" type="text" placeholder="Maya" />
|
||||
</label>
|
||||
|
||||
<label class="vf-field">
|
||||
<span class="vf-label">Suburb / location</span>
|
||||
<input
|
||||
id={`${idPrefix}-location`}
|
||||
name="location"
|
||||
type="text"
|
||||
placeholder="Mt Eden, Grey Lynn, Ponsonby…"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<fieldset class="vf-choice-group">
|
||||
<legend class="vf-label">What feels closest right now?</legend>
|
||||
<p class="vf-helper">
|
||||
Not sure is completely fine. We can sort that out at the Meet & Greet.
|
||||
</p>
|
||||
<div class="vf-choices">
|
||||
<label class="vf-choice">
|
||||
<input type="radio" name={`${idPrefix}-service-fit`} value="tiny-gang" />
|
||||
<span>Tiny Gang Pack Walks</span>
|
||||
</label>
|
||||
<label class="vf-choice">
|
||||
<input type="radio" name={`${idPrefix}-service-fit`} value="one-to-one" />
|
||||
<span>1:1 Walks</span>
|
||||
</label>
|
||||
<label class="vf-choice">
|
||||
<input type="radio" name={`${idPrefix}-service-fit`} value="puppy-visits" />
|
||||
<span>Puppy Visits</span>
|
||||
</label>
|
||||
<label class="vf-choice">
|
||||
<input type="radio" name={`${idPrefix}-service-fit`} value="not-sure" checked />
|
||||
<span>Not sure yet</span>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<label class="vf-field vf-field--full">
|
||||
<span class="vf-label">About your dog</span>
|
||||
<textarea
|
||||
id={`${idPrefix}-about-dog`}
|
||||
name="aboutDog"
|
||||
rows="5"
|
||||
placeholder="Tell us about age, size, confidence, leash manners, how they feel around other dogs, and anything that helps us make the right recommendation."
|
||||
></textarea>
|
||||
</label>
|
||||
|
||||
<div class="vf-note-row" aria-label="Helpful notes">
|
||||
<article class="vf-note">
|
||||
<span class="vf-note-title">Nervous dogs</span>
|
||||
<p>
|
||||
If your dog is shy, easily overwhelmed, or still building confidence, mention it here.
|
||||
That often points us toward a calmer first step.
|
||||
</p>
|
||||
</article>
|
||||
<article class="vf-note">
|
||||
<span class="vf-note-title">Tiny Gang suitability</span>
|
||||
<p>
|
||||
Our small-group walks work best for dogs who enjoy the right company, gentle
|
||||
structure, and a routine they can settle into.
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
{#if step === 2}
|
||||
<section class="vf-group" aria-labelledby={`${idPrefix}-owner-group`}>
|
||||
<div class="vf-group-head">
|
||||
<p class="vf-kicker" id={`${idPrefix}-owner-group`}>Owner details</p>
|
||||
<p class="vf-group-copy">
|
||||
So Aless can reply properly and arrange a free Meet & Greet without back-and-forth.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="vf-grid vf-grid--three">
|
||||
<label class="vf-field">
|
||||
<span class="vf-label">Owner name</span>
|
||||
<input id={`${idPrefix}-owner-name`} name="ownerName" type="text" placeholder="Your full name" />
|
||||
</label>
|
||||
|
||||
<label class="vf-field">
|
||||
<span class="vf-label">Email</span>
|
||||
<input id={`${idPrefix}-email`} name="email" type="email" placeholder="you@example.com" />
|
||||
</label>
|
||||
|
||||
<label class="vf-field">
|
||||
<span class="vf-label">Phone</span>
|
||||
<input id={`${idPrefix}-phone`} name="phone" type="tel" placeholder="021 123 4567" />
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<article class="vf-owner-note">
|
||||
<span class="vf-note-title">What happens next</span>
|
||||
<p>
|
||||
We’ll reply personally, talk through fit, and arrange the free Meet & Greet if it
|
||||
feels like the right next step.
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
{/if}
|
||||
|
||||
<div class="vf-footer">
|
||||
<p class="vf-reassurance">
|
||||
Free Meet & Greet. No pressure. Just the right starting point for your dog.
|
||||
</p>
|
||||
<div class="vf-actions">
|
||||
{#if step === 2}
|
||||
<button type="button" class="vf-secondary" on:click={() => goToStep(1)}>Back</button>
|
||||
{/if}
|
||||
<button type="submit" class="vf-submit">
|
||||
{step === 1 ? 'Next: owner details' : submitLabel}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if submitted}
|
||||
<p class="vf-success" role="status">
|
||||
Demo only: this variant would hand the enquiry to Aless and prompt a free Meet & Greet.
|
||||
</p>
|
||||
{/if}
|
||||
</form>
|
||||
|
||||
<style>
|
||||
.vf-form {
|
||||
display: grid;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.vf-form--carded {
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.vf-header {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.vf-eyebrow {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
width: fit-content;
|
||||
min-height: 30px;
|
||||
padding: 0 12px;
|
||||
border-radius: 999px;
|
||||
background: rgba(33, 48, 33, 0.07);
|
||||
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.05);
|
||||
color: var(--gw-green);
|
||||
font-family: var(--font-head);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.vf-title {
|
||||
margin: 0;
|
||||
color: #11171b;
|
||||
font-family: var(--font-head);
|
||||
font-size: clamp(26px, 3vw, 34px);
|
||||
line-height: 1.06;
|
||||
letter-spacing: -0.04em;
|
||||
}
|
||||
|
||||
.vf-subtitle {
|
||||
margin: 0;
|
||||
color: #59606d;
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.vf-stepper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.vf-step {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-height: 44px;
|
||||
padding: 0 14px 0 10px;
|
||||
border: none;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.84);
|
||||
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.06);
|
||||
color: #50555c;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
background 0.18s ease,
|
||||
color 0.18s ease,
|
||||
transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
.vf-step.active {
|
||||
background: rgba(33, 48, 33, 0.08);
|
||||
color: #11171b;
|
||||
}
|
||||
|
||||
.vf-step:disabled {
|
||||
cursor: default;
|
||||
opacity: 0.55;
|
||||
}
|
||||
|
||||
.vf-step-number {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 10px;
|
||||
background: var(--gw-green);
|
||||
color: var(--yellow);
|
||||
font-family: var(--font-head);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.vf-step-label {
|
||||
font-family: var(--font-head);
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.vf-step-divider {
|
||||
width: 26px;
|
||||
height: 1px;
|
||||
background: rgba(17, 20, 24, 0.1);
|
||||
}
|
||||
|
||||
.vf-lead {
|
||||
margin: 0;
|
||||
color: #4c5056;
|
||||
font-size: 15px;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
.vf-group {
|
||||
display: grid;
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.vf-form--carded .vf-group {
|
||||
padding: 22px;
|
||||
border-radius: 24px;
|
||||
background: linear-gradient(180deg, rgba(251, 251, 251, 0.98) 0%, rgba(247, 248, 246, 1) 100%);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px rgba(17, 20, 24, 0.06),
|
||||
0 12px 28px rgba(17, 20, 24, 0.06);
|
||||
}
|
||||
|
||||
.vf-group-head {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.vf-kicker {
|
||||
margin: 0;
|
||||
color: var(--gw-green);
|
||||
font-family: var(--font-head);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.vf-group-copy {
|
||||
margin: 0;
|
||||
color: #59606d;
|
||||
font-size: 14px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.vf-grid {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.vf-grid--two {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.vf-grid--three {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.vf-field {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.vf-field--full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.vf-label,
|
||||
.vf-choice-group legend {
|
||||
color: #16181d;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
.vf-field input,
|
||||
.vf-field textarea {
|
||||
width: 100%;
|
||||
border: none;
|
||||
border-radius: 18px;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
box-shadow:
|
||||
inset 0 0 0 1px rgba(17, 20, 24, 0.08),
|
||||
0 1px 0 rgba(255, 255, 255, 0.3);
|
||||
color: #1f2421;
|
||||
padding: 15px 16px;
|
||||
font-size: 15px;
|
||||
line-height: 1.45;
|
||||
outline: none;
|
||||
transition:
|
||||
box-shadow 0.18s ease,
|
||||
transform 0.18s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
background 0.18s ease;
|
||||
}
|
||||
|
||||
.vf-field textarea {
|
||||
resize: vertical;
|
||||
min-height: 132px;
|
||||
}
|
||||
|
||||
.vf-field input:focus-visible,
|
||||
.vf-field textarea:focus-visible,
|
||||
.vf-choice input:focus-visible + span,
|
||||
.vf-step:focus-visible,
|
||||
.vf-secondary:focus-visible {
|
||||
box-shadow:
|
||||
inset 0 0 0 2px rgba(255, 209, 0, 0.7),
|
||||
0 0 0 4px rgba(255, 209, 0, 0.14);
|
||||
background: #fff;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.vf-choice-group {
|
||||
display: grid;
|
||||
gap: 10px;
|
||||
min-width: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.vf-helper {
|
||||
margin: 0;
|
||||
color: #687076;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.vf-choices {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.vf-choice {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.vf-choice input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.vf-choice span {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 42px;
|
||||
padding: 0 14px;
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.08);
|
||||
color: #2f3134;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
transition:
|
||||
box-shadow 0.18s ease,
|
||||
background 0.18s ease,
|
||||
color 0.18s ease,
|
||||
transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
.vf-choice input:checked + span {
|
||||
background: rgba(255, 209, 0, 0.18);
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 209, 0, 0.34);
|
||||
color: #16181d;
|
||||
}
|
||||
|
||||
.vf-note-row {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.vf-note,
|
||||
.vf-owner-note {
|
||||
padding: 16px 16px 15px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.vf-note {
|
||||
background: rgba(33, 48, 33, 0.05);
|
||||
box-shadow: inset 0 0 0 1px rgba(33, 48, 33, 0.06);
|
||||
}
|
||||
|
||||
.vf-owner-note {
|
||||
background: rgba(255, 209, 0, 0.12);
|
||||
box-shadow: inset 0 0 0 1px rgba(255, 209, 0, 0.16);
|
||||
}
|
||||
|
||||
.vf-note-title {
|
||||
display: block;
|
||||
margin-bottom: 6px;
|
||||
color: var(--gw-green);
|
||||
font-family: var(--font-head);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.vf-note p,
|
||||
.vf-owner-note p {
|
||||
margin: 0;
|
||||
color: #4c5056;
|
||||
font-size: 13px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.vf-footer {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.vf-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.vf-reassurance {
|
||||
margin: 0;
|
||||
color: #59606d;
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.vf-secondary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 52px;
|
||||
padding: 0 18px;
|
||||
border: none;
|
||||
border-radius: 999px;
|
||||
background: rgba(33, 48, 33, 0.07);
|
||||
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.06);
|
||||
color: var(--gw-green);
|
||||
font-family: var(--font-head);
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vf-submit {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 52px;
|
||||
width: fit-content;
|
||||
padding: 0 22px;
|
||||
border: none;
|
||||
border-radius: 999px;
|
||||
background: linear-gradient(135deg, #ffd54a, var(--yellow-soft));
|
||||
box-shadow:
|
||||
inset 0 -2px 0 rgba(0, 0, 0, 0.08),
|
||||
0 12px 24px rgba(17, 20, 24, 0.1);
|
||||
color: #111;
|
||||
font-family: var(--font-head);
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
cursor: pointer;
|
||||
transition:
|
||||
transform 0.18s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
box-shadow 0.18s ease,
|
||||
filter 0.18s ease;
|
||||
}
|
||||
|
||||
.vf-submit:focus-visible {
|
||||
outline: 3px solid rgba(255, 209, 0, 0.28);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
.vf-success {
|
||||
margin: 0;
|
||||
padding: 14px 16px;
|
||||
border-radius: 18px;
|
||||
background: rgba(33, 48, 33, 0.07);
|
||||
box-shadow: inset 0 0 0 1px rgba(33, 48, 33, 0.08);
|
||||
color: var(--gw-green);
|
||||
font-size: 14px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.vf-form--conversational .vf-label,
|
||||
.vf-form--conversational .vf-choice-group legend {
|
||||
font-family: var(--font-head);
|
||||
font-size: 16px;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.vf-form--conversational .vf-field input,
|
||||
.vf-form--conversational .vf-field textarea {
|
||||
border-radius: 22px;
|
||||
padding: 17px 18px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.vf-form--minimal .vf-group-copy,
|
||||
.vf-form--minimal .vf-helper,
|
||||
.vf-form--minimal .vf-reassurance,
|
||||
.vf-form--minimal .vf-subtitle {
|
||||
color: #6b7077;
|
||||
}
|
||||
|
||||
.vf-form--minimal .vf-field input,
|
||||
.vf-form--minimal .vf-field textarea,
|
||||
.vf-form--minimal .vf-choice span {
|
||||
box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.06);
|
||||
}
|
||||
|
||||
@media (hover: hover) {
|
||||
.vf-step:hover,
|
||||
.vf-secondary:hover,
|
||||
.vf-choice:hover span,
|
||||
.vf-submit:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.vf-submit:hover {
|
||||
box-shadow:
|
||||
inset 0 -2px 0 rgba(0, 0, 0, 0.08),
|
||||
0 16px 28px rgba(17, 20, 24, 0.12);
|
||||
filter: brightness(1.02);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.vf-grid--two,
|
||||
.vf-grid--three,
|
||||
.vf-note-row {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.vf-stepper {
|
||||
align-items: stretch;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.vf-step {
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.vf-step-divider {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.vf-form {
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.vf-form--carded .vf-group {
|
||||
padding: 18px;
|
||||
border-radius: 22px;
|
||||
}
|
||||
|
||||
.vf-field input,
|
||||
.vf-field textarea {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.vf-actions {
|
||||
flex-direction: column-reverse;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.vf-secondary,
|
||||
.vf-submit {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user