Phase 4: implement full static site (Eleventy, 15 pages, CSS, JS)
This commit is contained in:
161
src/contact.njk
Normal file
161
src/contact.njk
Normal file
@@ -0,0 +1,161 @@
|
||||
---
|
||||
layout: layouts/base.njk
|
||||
title: "Request a Quote"
|
||||
description: "Request a quote from Diana — San Francisco's trusted handywoman. Tell her about your project and she'll get back to you within 1–2 business days."
|
||||
---
|
||||
|
||||
{# ── Page hero ─────────────────────────────────────────────────────────────── #}
|
||||
<section class="page-hero bg-graphite">
|
||||
<div class="page-hero__inner container">
|
||||
<p class="section-eyebrow">Get in touch</p>
|
||||
<h1 class="page-hero__title">Request a Quote.</h1>
|
||||
<p class="page-hero__lead">Tell Diana about your project. She responds within 1–2 business days.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# ── Contact grid ──────────────────────────────────────────────────────────── #}
|
||||
<section class="contact-page section">
|
||||
<div class="contact-page__grid container">
|
||||
|
||||
{# ── Form column ─────────────────────────────────────────────────────── #}
|
||||
<div>
|
||||
<form class="quote-form" id="quote-form" novalidate aria-label="Quote request form">
|
||||
|
||||
{# Honeypot — hidden from real users, catches bots #}
|
||||
<div class="visually-trap" aria-hidden="true">
|
||||
<label for="website">Leave this blank</label>
|
||||
<input type="text" id="website" name="website" tabindex="-1" autocomplete="off">
|
||||
</div>
|
||||
|
||||
{# Error banner — shown by JS when form has validation errors #}
|
||||
<div class="form-error-banner" role="alert" aria-live="assertive" hidden>
|
||||
<p>Please correct the errors below before sending.</p>
|
||||
</div>
|
||||
|
||||
{# Name #}
|
||||
<div class="form-field">
|
||||
<label for="name">Your name <span aria-hidden="true">*</span></label>
|
||||
<input
|
||||
type="text"
|
||||
id="name"
|
||||
name="name"
|
||||
required
|
||||
autocomplete="name"
|
||||
aria-required="true"
|
||||
aria-describedby="name-error"
|
||||
>
|
||||
<p class="form-field__error" id="name-error" aria-live="polite"></p>
|
||||
</div>
|
||||
|
||||
{# Address / Location #}
|
||||
<div class="form-field">
|
||||
<label for="address">Project address <span aria-hidden="true">*</span></label>
|
||||
<input
|
||||
type="text"
|
||||
id="address"
|
||||
name="address"
|
||||
required
|
||||
autocomplete="off"
|
||||
aria-required="true"
|
||||
aria-describedby="address-hint address-error"
|
||||
>
|
||||
<p class="form-field__hint" id="address-hint">Where is the work located? City or full address.</p>
|
||||
<p class="form-field__error" id="address-error" aria-live="polite"></p>
|
||||
</div>
|
||||
|
||||
{# Phone #}
|
||||
<div class="form-field">
|
||||
<label for="phone">Phone number <span aria-hidden="true">*</span></label>
|
||||
<input
|
||||
type="tel"
|
||||
id="phone"
|
||||
name="phone"
|
||||
required
|
||||
inputmode="tel"
|
||||
autocomplete="tel"
|
||||
aria-required="true"
|
||||
aria-describedby="phone-error"
|
||||
>
|
||||
<p class="form-field__error" id="phone-error" aria-live="polite"></p>
|
||||
</div>
|
||||
|
||||
{# Email #}
|
||||
<div class="form-field">
|
||||
<label for="email">Email address <span aria-hidden="true">*</span></label>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
name="email"
|
||||
required
|
||||
inputmode="email"
|
||||
autocomplete="email"
|
||||
aria-required="true"
|
||||
aria-describedby="email-error"
|
||||
>
|
||||
<p class="form-field__error" id="email-error" aria-live="polite"></p>
|
||||
</div>
|
||||
|
||||
{# Project description #}
|
||||
<div class="form-field">
|
||||
<label for="description">Project description <span aria-hidden="true">*</span></label>
|
||||
<textarea
|
||||
id="description"
|
||||
name="description"
|
||||
rows="5"
|
||||
required
|
||||
aria-required="true"
|
||||
aria-describedby="description-hint description-char-count description-error"
|
||||
></textarea>
|
||||
<p class="form-field__hint" id="description-hint">What needs to be fixed, replaced, or improved?</p>
|
||||
<p class="form-field__char-count" id="description-char-count" aria-live="polite"></p>
|
||||
<p class="form-field__error" id="description-error" aria-live="polite"></p>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn--primary form__submit">Send My Request</button>
|
||||
|
||||
{# Success message — shown by JS after successful submission #}
|
||||
<div class="form-success" role="status" hidden>
|
||||
<p class="form-success__icon" aria-hidden="true">✓</p>
|
||||
<h2 class="form-success__title">Your request is on its way!</h2>
|
||||
<p class="form-success__body">Diana will review your request and get back to you within 1–2 business days. If your project is urgent, you can also reach her directly at <a href="{{ site.phone | telHref }}">{{ site.phoneDisplay }}</a>.</p>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{# ── Contact secondary column ─────────────────────────────────────────── #}
|
||||
<aside class="contact-secondary">
|
||||
<h2>Other ways to reach Diana</h2>
|
||||
|
||||
<div class="contact-secondary__method">
|
||||
<span class="contact-secondary__icon" aria-hidden="true">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
|
||||
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.69 12 19.79 19.79 0 0 1 1.61 3.4 2 2 0 0 1 3.6 1.22h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L7.91 8.78a16 16 0 0 0 6 6l.92-.92a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 21.5 16h.5a2 2 0 0 1 .02.92z"/>
|
||||
</svg>
|
||||
</span>
|
||||
<div>
|
||||
<p class="contact-secondary__label">Call or text</p>
|
||||
<a href="{{ site.phone | telHref }}" class="contact-secondary__value">{{ site.phoneDisplay }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="contact-secondary__method">
|
||||
<span class="contact-secondary__icon" aria-hidden="true">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false">
|
||||
<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/>
|
||||
<polyline points="22,6 12,13 2,6"/>
|
||||
</svg>
|
||||
</span>
|
||||
<div>
|
||||
<p class="contact-secondary__label">Email</p>
|
||||
<a href="mailto:{{ site.email }}" class="contact-secondary__value">{{ site.email }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>For urgent repairs, calling is fastest.</p>
|
||||
|
||||
<p class="contact-secondary__area">Diana serves {{ site.serviceArea }}.</p>
|
||||
</aside>
|
||||
|
||||
</div>
|
||||
</section>
|
||||
Reference in New Issue
Block a user