Add static SEO and FAQ foundations
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
const { heading = 'Frequently asked questions', items = [] } = Astro.props;
|
||||
if (!items.length) return;
|
||||
---
|
||||
<section class="section faq-section" aria-labelledby="faq-heading">
|
||||
<div class="shell narrow"><p class="eyebrow">Helpful answers</p><h2 id="faq-heading">{heading}</h2><div class="faq-list">{items.map((item) => <details><summary>{item.question}</summary><p>{item.answer}</p></details>)}</div></div>
|
||||
</section>
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import Faq from '../components/Faq.astro';
|
||||
import Hero from '../components/Hero.astro';
|
||||
import { isBlog, site } from '../lib/site-data.js';
|
||||
---
|
||||
@@ -8,6 +9,6 @@ import { isBlog, site } from '../lib/site-data.js';
|
||||
{isBlog ? <section class="section"><div class="shell"><div class="section-heading"><p class="eyebrow">The journal</p><h2>Small notes for happier dog days.</h2></div><div class="post-grid">{site.posts.map((post) => <article class="post-card"><p class="tag">{post.tag}</p><h3>{post.title}</h3><p>{post.excerpt}</p><footer>{post.date}</footer></article>)}</div><p class="phase-note">This static sample deliberately uses JSON. Markdown publishing starts only in the later, separately approved content-update phase.</p></div></section> : <>
|
||||
<section class="section"><div class="shell"><div class="section-heading split"><div><p class="eyebrow">The Happy Tails difference</p><h2>A familiar face, a thoughtful routine, a very happy dog.</h2></div><p>We keep our pack intentionally small, so every dog gets the calm attention and consistent care they deserve.</p></div><div class="feature-grid">{site.features.map((feature) => <article class="feature"><span>{feature.icon}</span><h3>{feature.title}</h3><p>{feature.description}</p></article>)}</div></div></section>
|
||||
<section class="section surface"><div class="shell story-grid"><img src={site.story.image} alt={site.story.imageAlt} loading="lazy" /><div><p class="eyebrow">Our story</p><h2>{site.story.heading}</h2><p class="lede">{site.story.copy}</p><a class="text-link" href="/about">Meet the team →</a></div></div></section>
|
||||
<section class="section"><div class="shell"><div class="section-heading"><p class="eyebrow">Loved by local families</p><h2>Five-star care, shared in their own words.</h2></div><div class="review-grid">{site.reviews.map((review) => <blockquote class="review"><div aria-label={`${review.rating} out of 5 stars`} class="stars">★★★★★</div><p>“{review.quote}”</p><footer>{review.author} <span>Google review</span></footer></blockquote>)}</div><p class="review-disclosure">Review cards are a presentation pattern. Before launch, display only reviews approved for reuse and preserve their source, date, rating, and attribution under the business’s Google review policy.</p></div></section>
|
||||
<section class="section"><div class="shell"><div class="section-heading"><p class="eyebrow">Loved by local families</p><h2>Five-star care, shared in their own words.</h2></div><div class="review-grid">{site.reviews.map((review) => <blockquote class="review"><div aria-label={`${review.rating} out of 5 stars`} class="stars">★★★★★</div><p>“{review.quote}”</p><footer>{review.author} <span>Google review</span></footer></blockquote>)}</div><p class="review-disclosure">Review cards are a presentation pattern. Before launch, display only reviews approved for reuse and preserve their source, date, rating, and attribution under the business’s Google review policy.</p></div></section><Faq items={site.faq} />
|
||||
</>}
|
||||
</BaseLayout>
|
||||
|
||||
@@ -51,5 +51,6 @@ nav a[aria-current='page'], nav a:hover { color: var(--ink); }
|
||||
.contact-grid { align-items: start; }.contact-details { margin-top: 2rem; font-style: normal; color: #52616b; }.contact-details p { margin-bottom: .8rem; }.contact-details a { color: var(--ink); font-weight: 700; }.contact-form { display: grid; gap: 1rem; padding: 2rem; background: var(--surface); border-radius: .85rem; }.contact-form label { display: grid; gap: .4rem; font-size: .9rem; font-weight: 700; }.contact-form input,.contact-form textarea { width: 100%; padding: .8rem; font: inherit; border: 1px solid #cbd5d1; border-radius: .35rem; background: #fff; }.contact-form button:disabled { cursor: not-allowed; opacity: .6; }.contact-form p { margin-bottom: 0; color: #66747d; font-size: .85rem; }
|
||||
.location-map { display: grid; grid-template-columns: .75fr 1.25fr; overflow: hidden; border: 1px solid #dce4e1; border-radius: 1rem; background: #fff; }.map-copy { padding: clamp(2rem, 5vw, 4rem); }.map-copy h3 { font-family: 'DM Serif Display', Georgia, serif; font-size: 2.25rem; font-weight: 400; line-height: 1.05; }.map-copy p:not(.eyebrow) { color: #52616b; }.location-map iframe { display: block; min-height: 360px; width: 100%; border: 0; filter: saturate(.8) contrast(.96); }
|
||||
.post-card { padding: 2rem; border-radius: .85rem; background: #fff; border: 1px solid #dce4e1; }.post-card h3 { font-family: 'DM Serif Display', Georgia, serif; font-size: 1.75rem; font-weight: 400; line-height: 1.1; }.post-card footer { color: #75828c; font-size: .85rem; }.not-found { min-height: 55vh; display: grid; place-items: center; }
|
||||
.narrow { width: min(760px, calc(100% - 3rem)); }.faq-list { border-top: 1px solid #dce4e1; }.faq-list details { border-bottom: 1px solid #dce4e1; padding: 1.1rem 0; }.faq-list summary { cursor: pointer; font-weight: 700; list-style: none; padding-right: 2rem; position: relative; }.faq-list summary::after { content: '+'; position: absolute; right: .25rem; color: var(--accent); font-size: 1.3rem; top: -.3rem; }.faq-list details[open] summary::after { content: '−'; }.faq-list p { margin: 1rem 2rem .2rem 0; color: #52616b; }
|
||||
.site-footer { padding: 4rem 0 1.25rem; background: var(--ink); color: #fff; }.site-footer .brand { color: #fff; }.site-footer p { color: #c5d0d6; max-width: 34ch; }.footer-grid { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 3rem; }.footer-link { display: block; margin: .6rem 0; color: #fff; text-decoration: none; }.footer-bottom { display: flex; justify-content: space-between; gap: 1rem; margin-top: 3rem; padding-top: 1.25rem; border-top: 1px solid #35505f; color: #c5d0d6; font-size: .85rem; }
|
||||
@media (max-width: 760px) { .shell { width: min(100% - 2rem, 1120px); }.menu-button { display: inline-flex; gap: .5rem; } .nav-wrap { min-height: 68px; } nav { display: none; position: absolute; top: 68px; right: 1rem; left: 1rem; padding: 1rem; background: #fff; border: 1px solid #e8ecea; border-radius: .6rem; box-shadow: 0 1rem 2rem #102a4320; } nav.is-open { display: grid; } .hero { background: var(--surface); }.hero-grid,.story-grid,.contact-grid,.section-heading.split,.page-intro-grid,.location-map { grid-template-columns: 1fr; gap: 2.5rem; }.page-intro img { max-width: 520px; }.hero-image { max-width: 520px; }.image-note { right: -.5rem; }.feature-grid,.review-grid,.service-grid,.post-grid { grid-template-columns: 1fr; }.service-card.featured,.service-card.featured:hover { transform: none; }.team-grid { grid-template-columns: 1fr; }.location-map iframe { min-height: 300px; }.footer-grid { grid-template-columns: 1fr; gap: 1.5rem; }.footer-bottom { display: block; }.footer-bottom span { display: block; margin-top: .5rem; } }
|
||||
|
||||
Reference in New Issue
Block a user