Skip to main content

Content & marketing

Hero code

Copy the implementation or inspect every file that belongs to this component unit.

resources/views/components/ui/hero.blade.php

@props([
    'announce' => null,
    'announceHref' => '#',
    'title',
    'description' => null,
    'grid' => true,
    'randomGlow' => false,
])

@php
    /*
    | Landing-page hero. Optional `announce` renders a pill link above the
    | headline. Place CTA buttons in the `actions` slot and a product mockup in
    | the `media` slot (rendered full-bleed below the copy with a gradient base).
    | Set `grid` to false to drop the grid backdrop and keep just the glow.
    | Set `randomGlow` to nudge the glow position once on load (skipped when the
    | visitor prefers reduced motion).
    |
    | Usage:
    |   <x-ui.hero announce="v1.0 is live" title="Ship faster" description="…">
    |       <x-slot:actions>…</x-slot:actions>
    |       <x-slot:media><x-ui.window>…</x-ui.window></x-slot:media>
    |   </x-ui.hero>
    */
    $glowClipPath = 'polygon(74% 44%, 100% 61%, 97% 26%, 85% 0, 80% 2%, 72% 32%, 60% 62%, 52% 68%, 47% 58%, 45% 34%, 27% 76%, 0 64%, 17% 100%, 27% 76%, 76% 97%, 74% 44%)';
@endphp

<section
    {{ $attributes->merge(['class' => 'relative overflow-hidden']) }}
    @if ($randomGlow)
        x-data="{
            glowX: 50,
            glowY: 0,
            pedestalInset: 32,
            init() {
                if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
                    return;
                }

                this.glowX = 38 + Math.random() * 24;
                this.glowY = -18 + Math.random() * 36;
                this.pedestalInset = 24 + Math.random() * 16;
            },
        }"
    @endif
>
    {{-- Grid backdrop + soft radial glow --}}
    @if ($grid)
        <div class="pointer-events-none absolute inset-0 -z-10 bg-grid opacity-[0.4] [mask-image:radial-gradient(ellipse_60%_50%_at_50%_0%,black,transparent)]" aria-hidden="true"></div>
    @endif
    <div class="pointer-events-none absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl" aria-hidden="true">
        <div
            @class([
                'relative aspect-[1155/678] w-[36rem] bg-gradient-to-tr from-brand-400 to-brand-600 opacity-20 sm:w-[72rem]',
                'left-1/2 -translate-x-1/2' => ! $randomGlow,
            ])
            @if ($randomGlow)
                :style="`left: ${glowX}%; transform: translateX(-50%) translateY(${glowY}px); clip-path: {{ $glowClipPath }}`"
            @else
                style="clip-path: {{ $glowClipPath }}"
            @endif
        ></div>
    </div>

    <div class="mx-auto max-w-3xl px-4 sm:px-6 lg:px-8 pt-20 pb-16 sm:pt-28 text-center">
        @if ($announce)
            <div class="mb-8 flex justify-center pt-1">
                <a href="{{ $announceHref }}" class="group relative inline-flex items-center gap-2 overflow-visible rounded-full border border-gray-200 dark:border-gray-800 bg-white/70 dark:bg-gray-900/70 backdrop-blur px-3 py-1.5 text-sm text-gray-600 dark:text-gray-300 shadow-sm transition hover:border-brand-300 dark:hover:border-brand-800">
                    <span class="pointer-events-none absolute left-0 top-0 z-10 -translate-x-1/2 -translate-y-1/2 inline-flex items-center gap-1 rounded-full bg-brand-600 px-2 py-0.5 text-xs font-semibold text-white shadow-sm ring-2 ring-white dark:ring-gray-900">
                        <x-ui.icon name="sparkle" weight="fill" size="xs" /> New
                    </span>
                    <span>{{ $announce }}</span>
                    <x-ui.icon name="arrow-right" weight="bold" size="xs" class="text-gray-400 transition group-hover:translate-x-0.5" />
                </a>
            </div>
        @endif

        <h1 class="text-4xl sm:text-6xl font-semibold tracking-tight text-gray-900 dark:text-white text-balance">
            {{ $title }}
        </h1>

        @if ($description)
            <p class="mt-6 text-lg sm:text-xl leading-relaxed text-gray-600 dark:text-gray-400 text-pretty">{{ $description }}</p>
        @endif

        @isset($actions)
            <div class="mt-10 flex flex-col sm:flex-row items-center justify-center gap-3">{{ $actions }}</div>
        @endisset
    </div>

    @isset($media)
        <div class="relative mx-auto max-w-6xl px-4 sm:px-6 lg:px-8 pb-20">
            {{-- gradient pedestal behind the mockup --}}
            <div
                @class([
                    'pointer-events-none absolute top-10 -z-10 h-full rounded-[2rem] bg-gradient-to-b from-brand-500/20 to-transparent blur-2xl',
                    'inset-x-8' => ! $randomGlow,
                ])
                @if ($randomGlow)
                    :style="`left: ${pedestalInset}px; right: ${pedestalInset}px`"
                @endif
                aria-hidden="true"
            ></div>
            {{ $media }}
        </div>
    @endisset
</section>