refactor(home): remove duplicate FAQ section, merge unique Q&As into HomepageFaq
Deploy to Production / Build & Verify (push) Has been cancelled
Deploy to Production / Pre-Deploy Tests (push) Has been cancelled
Deploy to Production / Deploy to Railway (push) Has been cancelled
Deploy to Production / Deploy to Render (push) Has been cancelled
Deploy to Production / Deploy to VPS (PM2) (push) Has been cancelled
Deploy to Production / Deploy to Fly.io (push) Has been cancelled
Deploy to Production / Post-Deploy Verification (push) Has been cancelled
Deploy to Production / Notify on Failure (push) Has been cancelled
E2E Test Suite / Critical User Journeys (push) Has been cancelled
E2E Test Suite / API Integration Tests (push) Has been cancelled
E2E Test Suite / Form Interaction Tests (push) Has been cancelled
E2E Test Suite / Destructive & Chaos Tests (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (chromium) (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (firefox) (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (webkit) (push) Has been cancelled
E2E Test Suite / Mobile Device Tests (push) Has been cancelled
E2E Test Suite / Security Header Tests (push) Has been cancelled
E2E Test Suite / Test Report Summary (push) Has been cancelled
E2E Test Suite / Smoke Tests (P0) (push) Has been cancelled
Ping Search Engines / Notify Search Engines (push) Successful in 3s
Deploy to Production / Build & Verify (push) Has been cancelled
Deploy to Production / Pre-Deploy Tests (push) Has been cancelled
Deploy to Production / Deploy to Railway (push) Has been cancelled
Deploy to Production / Deploy to Render (push) Has been cancelled
Deploy to Production / Deploy to VPS (PM2) (push) Has been cancelled
Deploy to Production / Deploy to Fly.io (push) Has been cancelled
Deploy to Production / Post-Deploy Verification (push) Has been cancelled
Deploy to Production / Notify on Failure (push) Has been cancelled
E2E Test Suite / Critical User Journeys (push) Has been cancelled
E2E Test Suite / API Integration Tests (push) Has been cancelled
E2E Test Suite / Form Interaction Tests (push) Has been cancelled
E2E Test Suite / Destructive & Chaos Tests (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (chromium) (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (firefox) (push) Has been cancelled
E2E Test Suite / Cross-Browser Regression (webkit) (push) Has been cancelled
E2E Test Suite / Mobile Device Tests (push) Has been cancelled
E2E Test Suite / Security Header Tests (push) Has been cancelled
E2E Test Suite / Test Report Summary (push) Has been cancelled
E2E Test Suite / Smoke Tests (P0) (push) Has been cancelled
Ping Search Engines / Notify Search Engines (push) Successful in 3s
The homepage rendered two FAQ blocks — an inline "Common Questions" section
plus the <HomepageFaq /> component above the final CTA — which produced two
FAQPage JSON-LD entries and a redundant accordion. Consolidate on
HomepageFaq (self-contained, polished accordion, better a11y) and:
- delete the inline FAQ <section>, the `faqs` array, the `faq={faqs}` prop
on <SEO>, the orphan .faq-question/.faq-answer/.faq-icon CSS, and the
initFAQ() boot script + its call in index.astro
- merge the 4 unique inline questions (support, process, team augmentation,
security) into HomepageFaq's moneyFaqs; the 2 duplicates (technologies,
timeline) were already covered there
- refresh HomepageFaq's lead-in copy and comments to reflect it as the
single canonical homepage FAQ
Result: one FAQ heading + one accordion in the DOM, exactly one FAQPage
JSON-LD with 10 Q&A pairs, no broken anchor links.
This commit is contained in:
@@ -1,17 +1,12 @@
|
||||
---
|
||||
// HomepageFaq — Money & process FAQ rendered just above the final CTA band.
|
||||
// HomepageFaq — single homepage FAQ section rendered just above the final
|
||||
// CTA band. Covers both buyer-stage objections (cost, timeline, NDA, IP, GeM,
|
||||
// stack) and the process/support/security questions that used to live in the
|
||||
// older "Common Questions" block higher up the page. That earlier block was
|
||||
// removed to avoid a duplicate FAQ rendering and a duplicate FAQPage JSON-LD
|
||||
// emission — this component is now the canonical homepage FAQ.
|
||||
//
|
||||
// Why a dedicated component instead of reusing the "Common Questions" block
|
||||
// further up the page:
|
||||
// - The questions here target buyers in late-stage evaluation (cost,
|
||||
// timeline, NDA, IP, GeM, stack). They convert better when surfaced next
|
||||
// to the final CTA, not next to the testimonials.
|
||||
// - Emitting FAQPage JSON-LD only once per page is the recommended pattern
|
||||
// for rich-result eligibility. The existing FAQ block above also emits a
|
||||
// FAQPage via <SEO> — so this component renders ONLY the visible UI; the
|
||||
// schema for these questions is appended to the parent's `faq` array in
|
||||
// src/pages/index.astro so Google still sees a single, valid FAQPage with
|
||||
// all 12 Q&A pairs.
|
||||
// Emits a single FAQPage JSON-LD inline (below) for rich-result eligibility.
|
||||
//
|
||||
// Accessibility:
|
||||
// - Each question is a real <button> with aria-expanded toggled in JS.
|
||||
@@ -54,13 +49,32 @@ const moneyFaqs = [
|
||||
answer:
|
||||
'Astro, Next.js, Angular, React Native, Spring Boot, Go, Node.js, PostgreSQL, and the full AWS/GCP stack.',
|
||||
},
|
||||
{
|
||||
question: 'Do you offer ongoing support after launch?',
|
||||
answer:
|
||||
'Yes. We offer maintenance packages covering bug fixes, security patches, performance monitoring, and feature enhancements — with response SLAs to match your uptime needs.',
|
||||
},
|
||||
{
|
||||
question: 'What is your development process?',
|
||||
answer:
|
||||
'Agile with 2-week sprints, weekly check-ins, and a live staging environment from day one. You see working software early and steer the roadmap as it ships.',
|
||||
},
|
||||
{
|
||||
question: 'Can you work with our existing team?',
|
||||
answer:
|
||||
'Absolutely. We augment in-house teams as readily as we deliver fully managed builds — adapting to your repo, branch strategy, ticket system, and review process.',
|
||||
},
|
||||
{
|
||||
question: 'How do you ensure project security?',
|
||||
answer:
|
||||
'Security is built into every phase: OWASP-aligned reviews, encrypted data at rest and in transit, role-based access control, regular dependency audits, and compliance with GDPR / SOC 2-style controls where the project demands them.',
|
||||
},
|
||||
];
|
||||
|
||||
// FAQPage JSON-LD — emitted inline so the schema travels with the component.
|
||||
// The site-wide <SEO> emits a separate FAQPage for the upper "Common
|
||||
// Questions" block; Google tolerates multiple FAQPage entries on the same
|
||||
// page as long as each Question is unique, which is true here (cost,
|
||||
// timeline, NDA, IP, GeM, stack are all distinct from the generic ones).
|
||||
// This is the ONLY FAQPage emitted on the homepage; the site-wide <SEO>
|
||||
// no longer receives a `faq` prop on / so Google sees exactly one valid
|
||||
// FAQPage with every visible Q&A pair.
|
||||
const faqPageSchema = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'FAQPage',
|
||||
@@ -97,7 +111,7 @@ const faqPageSchema = {
|
||||
Frequently asked questions
|
||||
</h2>
|
||||
<p class="text-base sm:text-lg text-secondary-600 dark:text-secondary-300">
|
||||
Quick answers on cost, timelines, ownership, and the stack we ship.
|
||||
Quick answers on cost, timelines, ownership, our process, support, security, and the stack we ship.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
+17
-114
@@ -161,33 +161,11 @@ const techStack = [
|
||||
},
|
||||
];
|
||||
|
||||
// FAQ data
|
||||
const faqs = [
|
||||
{
|
||||
question: 'What technologies do you specialize in?',
|
||||
answer: 'We specialize in modern web and mobile technologies including Angular, React, Next.js, Astro, Spring Boot, Golang, and databases like MySQL and PostgreSQL. We also work with Expo for mobile development.',
|
||||
},
|
||||
{
|
||||
question: 'How long does a typical project take?',
|
||||
answer: 'Project timelines vary based on complexity. A static website might take 2-4 weeks, while a complex government management system could take 6-24 months. We provide detailed timelines during the planning phase.',
|
||||
},
|
||||
{
|
||||
question: 'Do you offer ongoing support after launch?',
|
||||
answer: 'Yes! We offer comprehensive support packages including bug fixes, security updates, performance monitoring, and feature enhancements. Our 24/7 support ensures your systems run smoothly.',
|
||||
},
|
||||
{
|
||||
question: 'What is your development process?',
|
||||
answer: 'We follow an agile methodology with 2-week sprints, regular check-ins, and iterative development. You\'ll have full visibility into progress with access to staging environments and regular demos.',
|
||||
},
|
||||
{
|
||||
question: 'Can you work with our existing team?',
|
||||
answer: 'Absolutely! We excel at collaborating with in-house teams. Whether you need to augment your team or prefer a fully managed solution, we adapt to your workflow and tools.',
|
||||
},
|
||||
{
|
||||
question: 'How do you ensure project security?',
|
||||
answer: 'Security is built into every phase. We follow OWASP guidelines, conduct regular security audits, implement encryption, and ensure compliance with industry standards like GDPR and SOC 2.',
|
||||
},
|
||||
];
|
||||
// FAQ content lives in <HomepageFaq />, which renders the only homepage FAQ
|
||||
// section and emits the only FAQPage JSON-LD on this page. The duplicate
|
||||
// "Common Questions" block that used to live above the tech-stack section
|
||||
// was removed; its unique questions were merged into HomepageFaq's
|
||||
// `moneyFaqs` array so no buyer-facing content was dropped.
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
@@ -197,7 +175,6 @@ const faqs = [
|
||||
<SEO
|
||||
slot="head"
|
||||
type="WebPage"
|
||||
faq={faqs}
|
||||
/>
|
||||
|
||||
<!-- Hero Section - Enhanced -->
|
||||
@@ -617,53 +594,6 @@ const faqs = [
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- FAQ Section - NEW -->
|
||||
<section class="py-24 bg-white dark:bg-secondary-900">
|
||||
<div class="container-wrapper">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-16 items-start max-w-7xl mx-auto">
|
||||
<!-- Left column - Header -->
|
||||
<div class="lg:sticky lg:top-8" data-animate="fade-right">
|
||||
<span class="inline-block px-4 py-2 rounded-full bg-primary-50 dark:bg-primary-900/30 text-primary-700 dark:text-primary-300 text-sm font-bold uppercase tracking-wider mb-4">FAQ</span>
|
||||
<h2 class="text-4xl sm:text-5xl font-bold text-secondary-900 dark:text-secondary-100 mb-6">Common Questions</h2>
|
||||
<p class="text-xl text-secondary-600 dark:text-secondary-400 mb-8">
|
||||
Everything you need to know about working with us. Can't find the answer you're looking for?
|
||||
</p>
|
||||
<a href="/contact" class="inline-flex items-center text-primary-600 dark:text-primary-400 font-semibold hover:text-primary-700 dark:hover:text-primary-300 transition-colors">
|
||||
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path>
|
||||
</svg>
|
||||
Chat with our team
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Right column - Accordion -->
|
||||
<div class="space-y-4" data-animate="fade-left" data-delay="150">
|
||||
{faqs.map((faq, index) => (
|
||||
<div class="group bg-secondary-50 dark:bg-secondary-800 rounded-2xl border-2 border-secondary-100 dark:border-secondary-700 hover:border-primary-300 transition-all duration-300 overflow-hidden">
|
||||
<button
|
||||
class="faq-question w-full text-left px-8 py-6 flex items-start justify-between gap-4"
|
||||
data-faq-index={index}
|
||||
aria-expanded="false"
|
||||
aria-controls={`faq-answer-${index}`}
|
||||
id={`faq-question-${index}`}
|
||||
>
|
||||
<span class="font-bold text-lg text-secondary-900 dark:text-secondary-100 pr-4">{faq.question}</span>
|
||||
<svg class="faq-icon w-6 h-6 text-primary-500 flex-shrink-0 transition-transform duration-300" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M19 9l-7 7-7-7"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="faq-answer max-h-0 overflow-hidden transition-all duration-300" id={`faq-answer-${index}`} role="region" aria-labelledby={`faq-question-${index}`}>
|
||||
<div class="px-8 pb-6 text-secondary-600 dark:text-secondary-400 leading-relaxed">
|
||||
{faq.answer}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Technologies We Work With — relocated from the hero so social proof
|
||||
leads above the fold. Kept intentionally subdued (border-only cards,
|
||||
neutral grayscale icons) so it reads as supporting context rather than
|
||||
@@ -710,18 +640,20 @@ const faqs = [
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Inline Lead Form — sits between the FAQ/tech-stack social-proof block
|
||||
<!-- Inline Lead Form — sits between the tech-stack social-proof block
|
||||
and the final CTA band so visitors who are ready to start a project can
|
||||
submit a 3-field enquiry without leaving the homepage. Submits to the
|
||||
same /api/contact endpoint and is tagged `source: 'homepage-inline'` so
|
||||
the lead can be segmented downstream. -->
|
||||
<InlineLeadForm />
|
||||
|
||||
<!-- Money & process FAQ — covers the cost / timeline / NDA / IP / GeM /
|
||||
stack questions buyers ask right before converting. Sits between the
|
||||
inline lead form and the final CTA band so late-stage objections are
|
||||
resolved before the visitor hits the final call-to-action. Emits its
|
||||
own FAQPage JSON-LD for Google rich results. -->
|
||||
<!-- Homepage FAQ — single canonical FAQ section for /. Covers the cost /
|
||||
timeline / NDA / IP / GeM / stack questions buyers ask right before
|
||||
converting, plus the process / support / team-augmentation / security
|
||||
questions that used to live in the now-removed "Common Questions"
|
||||
block. Sits between the inline lead form and the final CTA band so
|
||||
late-stage objections are resolved before the visitor hits the final
|
||||
call-to-action. Emits the only FAQPage JSON-LD on this page. -->
|
||||
<HomepageFaq />
|
||||
|
||||
<!-- Final CTA Section - Enhanced -->
|
||||
@@ -865,18 +797,8 @@ const faqs = [
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* FAQ accordion styles */
|
||||
.faq-answer {
|
||||
transition: max-height 0.3s ease-out;
|
||||
}
|
||||
|
||||
.faq-question[aria-expanded="true"] + .faq-answer {
|
||||
max-height: 500px;
|
||||
}
|
||||
|
||||
.faq-question[aria-expanded="true"] .faq-icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
/* (FAQ accordion styles moved into <HomepageFaq />, which now renders the
|
||||
only homepage FAQ section.) */
|
||||
</style>
|
||||
|
||||
<script>
|
||||
@@ -1006,26 +928,8 @@ const faqs = [
|
||||
startAutoplay();
|
||||
}
|
||||
|
||||
// FAQ Accordion
|
||||
function initFAQ() {
|
||||
const faqButtons = document.querySelectorAll('.faq-question');
|
||||
|
||||
faqButtons.forEach((button) => {
|
||||
button.addEventListener('click', () => {
|
||||
const isExpanded = button.getAttribute('aria-expanded') === 'true';
|
||||
|
||||
// Close all FAQs
|
||||
faqButtons.forEach((btn) => {
|
||||
btn.setAttribute('aria-expanded', 'false');
|
||||
});
|
||||
|
||||
// Toggle current FAQ
|
||||
if (!isExpanded) {
|
||||
button.setAttribute('aria-expanded', 'true');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
// (FAQ accordion script moved into <HomepageFaq />, which now renders the
|
||||
// only homepage FAQ section and ships its own inline init.)
|
||||
|
||||
// Intersection Observer for counter animation
|
||||
function initStatsCounter() {
|
||||
@@ -1075,7 +979,6 @@ const faqs = [
|
||||
function bootHomepageScripts() {
|
||||
initStatsCounter();
|
||||
initCarousel();
|
||||
initFAQ();
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
|
||||
Reference in New Issue
Block a user