feat(home): conversion-rate optimization pass on homepage
E2E Test Suite / Smoke Tests (P0) (push) Failing after 9m26s
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
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
Ping Search Engines / Notify Search Engines (push) Failing after 12m53s
Deploy to Production / Build & Verify (push) Blocked by required conditions
Deploy to Production / Pre-Deploy Tests (push) Blocked by required conditions
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 / Smoke Tests (P0) (push) Failing after 9m26s
E2E Test Suite / Critical User Journeys (push) Has been skipped
E2E Test Suite / API Integration Tests (push) Has been skipped
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
Ping Search Engines / Notify Search Engines (push) Failing after 12m53s
Deploy to Production / Build & Verify (push) Blocked by required conditions
Deploy to Production / Pre-Deploy Tests (push) Blocked by required conditions
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
Hero
- Tightened H1 to a benefit-led, audience-first value prop
("Custom Software That Powers Enterprises & Governments")
- Replaced generic subhead with a ~135-char outcome line that names
the audience (startups, enterprises, government bodies)
- Swapped primary CTA copy to an action verb ("Get a free consultation")
and secondary to "See our work"; added source query params + data-cta
hooks so analytics can attribute CTA clicks
- Added a micro-trust line under the CTAs (free 30-min call, reply within
1 business day, no commitment)
Social proof
- New ClientLogos.astro component rendered below the hero. Grayscale
strip with hover pop, image+wordmark fallback, TODO documenting the
five required SVG assets in public/images/clients/
- Default roster sourced from the live portfolio (PLNR, RENTEC, IIT
Patna, MOC Soft Technologies, Govt. of Bihar)
- Existing testimonials carousel left intact (3 quotes with name/role)
Services preview
- Reframed the 4 cards around outcome headlines and added deep links
to /services#<slug> for each service detail section
- Renamed "Learn More" to "Learn more" and made it a real <a> link
with aria-label for screen readers
Final CTA band
- New conversion-focused headline ("Ready to ship your next production
system?") and a one-line offer with explicit response SLA
- Added a "what you'll get" reassurance row (discovery call, fixed-price
scope, NDA on request)
- Primary CTA now "Get my free consultation" with source attribution;
secondary "See case studies" preserved
- Process-section CTA renamed to "Book a discovery call" and tagged
SEO
- Updated meta description on BaseLayout invocation to match the new
positioning; FAQPage schema and existing structured data untouched
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
---
|
||||
/**
|
||||
* ClientLogos Component
|
||||
*
|
||||
* Social-proof strip of client/partner logos shown beneath the hero on the
|
||||
* homepage. Renders as a grayscale, lazy-loaded grid that pops to full colour
|
||||
* on hover so the section stays subtle but credible.
|
||||
*
|
||||
* The component accepts an optional `clients` prop. Each entry can carry:
|
||||
* - name: display name and accessible alt text (required)
|
||||
* - logo: path to a logo image asset (optional). When provided the
|
||||
* image is lazy-loaded and rendered grayscale; otherwise the
|
||||
* name is rendered as a typographic wordmark fallback so the
|
||||
* strip still renders intentionally while real assets are
|
||||
* being collected.
|
||||
* - href: optional outbound URL or internal anchor (e.g. a portfolio
|
||||
* case study). Omitted entries render as non-interactive items.
|
||||
* - subtitle: optional one-liner under the wordmark (e.g. "11 districts").
|
||||
*
|
||||
* If no `clients` prop is supplied the component uses a sensible default set
|
||||
* sourced from the active WorkRoot portfolio (PLNR, RENTEC, IIT Patna, MOC
|
||||
* Soft Technologies, Government of Bihar). When the real logo assets land
|
||||
* in `public/images/clients/<slug>.svg` simply add the `logo` field to the
|
||||
* matching entry (see TODO block in this file) and the component will swap
|
||||
* the wordmark for the image automatically.
|
||||
*
|
||||
* @prop {Array<{ name: string; logo?: string; href?: string; subtitle?: string }>} [clients]
|
||||
* @prop {string} [heading] - Eyebrow text rendered above the strip
|
||||
* @prop {'light' | 'dark'} [theme] - 'light' for white sections, 'dark' for
|
||||
* dark/hero adjacent placement
|
||||
* @prop {string} [class] - Extra classes merged onto the wrapper section
|
||||
*/
|
||||
|
||||
interface ClientEntry {
|
||||
name: string;
|
||||
logo?: string;
|
||||
href?: string;
|
||||
subtitle?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
clients?: ClientEntry[];
|
||||
heading?: string;
|
||||
theme?: 'light' | 'dark';
|
||||
class?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
clients,
|
||||
heading = 'Trusted by teams shipping production software',
|
||||
theme = 'light',
|
||||
class: extraClass = '',
|
||||
} = Astro.props;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Default client roster — sourced from the live portfolio and testimonials.
|
||||
// TODO(frontend-specialist): drop real SVG/PNG wordmarks into
|
||||
// public/images/clients/<slug>.svg
|
||||
// and populate the `logo` field below. Required asset slugs:
|
||||
// - plnr.svg (PLNR Financing platform)
|
||||
// - rentec.svg (RENTEC / FPC Cart)
|
||||
// - iit-patna.svg (IIT Patna University Management)
|
||||
// - moc-soft.svg (MOC Soft Technologies)
|
||||
// - gov-bihar.svg (Government of Bihar — Police Management / SCMS)
|
||||
// Logos should be supplied as monochrome SVG on a transparent background and
|
||||
// sized roughly 160 × 48 — the grayscale filter handles the rest.
|
||||
// -----------------------------------------------------------------------------
|
||||
const defaultClients: ClientEntry[] = [
|
||||
{ name: 'PLNR', subtitle: 'Financing Platform' },
|
||||
{ name: 'RENTEC', subtitle: 'FPC Cart' },
|
||||
{ name: 'IIT Patna', subtitle: 'University System' },
|
||||
{ name: 'MOC Soft Technologies', subtitle: 'Enterprise Partner' },
|
||||
{ name: 'Govt. of Bihar', subtitle: '11 Districts' },
|
||||
];
|
||||
|
||||
const items: ClientEntry[] = clients && clients.length > 0 ? clients : defaultClients;
|
||||
|
||||
const isDark = theme === 'dark';
|
||||
|
||||
const sectionClass = [
|
||||
'relative',
|
||||
isDark
|
||||
? 'bg-secondary-900'
|
||||
: 'bg-white dark:bg-secondary-900',
|
||||
extraClass,
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
const eyebrowClass = isDark
|
||||
? 'text-xs sm:text-sm uppercase tracking-[0.2em] text-secondary-400 font-semibold'
|
||||
: 'text-xs sm:text-sm uppercase tracking-[0.2em] text-secondary-500 dark:text-secondary-400 font-semibold';
|
||||
|
||||
const wordmarkClass = isDark
|
||||
? 'text-lg sm:text-xl font-bold text-white/80 group-hover:text-white transition-colors'
|
||||
: 'text-lg sm:text-xl font-bold text-secondary-700 dark:text-secondary-200 group-hover:text-secondary-900 dark:group-hover:text-white transition-colors';
|
||||
|
||||
const subtitleClass = isDark
|
||||
? 'block text-[11px] uppercase tracking-wider text-secondary-500 mt-1'
|
||||
: 'block text-[11px] uppercase tracking-wider text-secondary-400 dark:text-secondary-500 mt-1';
|
||||
|
||||
const imageFilter = 'grayscale opacity-70 group-hover:grayscale-0 group-hover:opacity-100 transition-all duration-300';
|
||||
---
|
||||
|
||||
<section class={sectionClass} aria-label="Clients and partners">
|
||||
<div class="container-wrapper py-12 sm:py-16">
|
||||
<p class={`text-center mb-8 ${eyebrowClass}`}>{heading}</p>
|
||||
|
||||
<ul
|
||||
class="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-x-8 gap-y-10 items-center justify-items-center"
|
||||
role="list"
|
||||
>
|
||||
{items.map((client) => {
|
||||
const Wrapper = client.href ? 'a' : 'div';
|
||||
const wrapperProps = client.href
|
||||
? { href: client.href, 'aria-label': `Learn more about ${client.name}` }
|
||||
: { 'aria-label': client.name };
|
||||
return (
|
||||
<li class="w-full flex justify-center">
|
||||
<Wrapper
|
||||
{...wrapperProps}
|
||||
class={`group flex flex-col items-center justify-center text-center w-full max-w-[180px] min-h-[64px] focus:outline-none focus:ring-2 focus:ring-primary-400 rounded-md ${client.href ? 'cursor-pointer' : ''}`}
|
||||
>
|
||||
{client.logo ? (
|
||||
<img
|
||||
src={client.logo}
|
||||
alt={`${client.name} logo`}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
width="160"
|
||||
height="48"
|
||||
class={`h-10 sm:h-12 w-auto object-contain ${imageFilter}`}
|
||||
/>
|
||||
) : (
|
||||
<span class={wordmarkClass}>{client.name}</span>
|
||||
)}
|
||||
{client.subtitle && (
|
||||
<span class={subtitleClass}>{client.subtitle}</span>
|
||||
)}
|
||||
</Wrapper>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
Reference in New Issue
Block a user