Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,12 @@ ANYSTACK_TRIAL_POLICY_ID=

FILAMENT_USERS=

# Public subscribe endpoint for the newsletter list, and the honeypot field name
# configured on it. Both default to the live NativePHP list in config/services.php,
# so only set these to point at a different Mailcoach list.
# MAILCOACH_NEWSLETTER_SUBSCRIBE_URL=
# MAILCOACH_HONEYPOT_FIELD=

BIFROST_API_KEY=your-secure-api-key-here

TURNSTILE_SITE_KEY=
Expand Down
17 changes: 17 additions & 0 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,23 @@
'key' => env('ANYSTACK_API_KEY'),
],

'mailcoach' => [
/*
* The public subscribe endpoint for the NativePHP newsletter list. Forms post
* straight to Mailcoach, which redirects back to the pages configured on the
* list (see the `newsletter.*` routes).
*/
'newsletter_subscribe_url' => env(
'MAILCOACH_NEWSLETTER_SUBSCRIBE_URL',
'https://simonhamp.mailcoach.app/subscribe/79a8941f-a008-4a6a-b81e-e4bb54d66755',
),

/*
* The honeypot field name configured on the list. It must be submitted empty.
*/
'honeypot_field' => env('MAILCOACH_HONEYPOT_FIELD', 'pet'),
],

'bifrost' => [
'api_key' => env('BIFROST_API_KEY'),
],
Expand Down
16 changes: 11 additions & 5 deletions resources/views/components/footer.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,13 @@ class="flex flex-wrap items-center justify-center gap-2.5 *:opacity-0"
}
"
>
<a
href="/newsletter"
class="group relative z-0 flex max-w-105 items-center gap-6 overflow-hidden rounded-2xl bg-cyan-50/50 py-5 pr-7 pl-6 ring-1 ring-black/5 transition duration-300 ease-in-out hover:bg-cyan-50 hover:ring-black/10 dark:bg-mirage dark:hover:bg-haiti dark:hover:ring-cloud"
<button
type="button"
x-on:click="
$dispatch('open-newsletter-modal')
window.fathom?.trackEvent('newsletter_footer_click')
"
class="group relative z-0 flex max-w-105 items-center gap-6 overflow-hidden rounded-2xl bg-cyan-50/50 py-5 pr-7 pl-6 text-left ring-1 ring-black/5 transition duration-300 ease-in-out hover:bg-cyan-50 hover:ring-black/10 dark:bg-mirage dark:hover:bg-haiti dark:hover:ring-cloud"
>
{{-- Decorative circle --}}
<div
Expand Down Expand Up @@ -123,7 +127,9 @@ class="transition duration-300 will-change-transform group-hover:scale-105"
<p
class="leading-relaxed opacity-70 transition duration-300 will-change-transform group-hover:translate-x-0.5"
>
Get the latest NativePHP updates and news delivered
Get a
<b class="font-semibold">10% discount code</b>
plus the latest NativePHP updates and news delivered
to your inbox.
</p>
</div>
Expand All @@ -150,7 +156,7 @@ class="leading-relaxed opacity-70 transition duration-300 will-change-transform
aria-hidden="true"
class="size-4 shrink-0"
/>
</a>
</button>
</div>
</div>

Expand Down
8 changes: 5 additions & 3 deletions resources/views/components/layout.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@
scrolled = window.scrollY > 1
})
"
class="font-poppins min-h-screen overflow-x-clip bg-white antialiased selection:bg-black selection:text-[#b4a9ff] dark:bg-[#050714] dark:text-white"
class="min-h-screen overflow-x-clip bg-white font-poppins antialiased selection:bg-black selection:text-[#b4a9ff] dark:bg-[#050714] dark:text-white"
>
<x-supernative-banner />
<x-newsletter-banner />

<x-navigation-bar />

Expand All @@ -130,7 +130,9 @@ class="mx-auto w-full max-w-5xl px-5 lg:px-3 xl:max-w-7xl 2xl:max-w-360"

<x-footer />

<x-impersonate::banner/>
<x-newsletter-modal />

<x-impersonate::banner />

@livewireScriptConfig
@fluxScripts
Expand Down
67 changes: 67 additions & 0 deletions resources/views/components/newsletter-banner.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<button
type="button"
x-on:click="
$dispatch('open-newsletter-modal')
window.fathom?.trackEvent('newsletter_banner_click')
"
data-site-banner
class="group relative z-30 flex w-full flex-col items-center justify-center gap-x-3 gap-y-2.5 overflow-hidden bg-gradient-to-r from-emerald-100 via-lime-50 to-emerald-100 px-5 py-3 select-none 3xs:flex-row dark:from-emerald-950/50 dark:via-lime-950/50 dark:to-emerald-950/50"
>
{{-- Label --}}
<div
class="flex items-center justify-center gap-3 transition duration-200 ease-in-out will-change-transform group-hover:-translate-x-0.5"
>
{{-- Icon --}}
<x-icons.gift
class="size-5 shrink-0 text-emerald-600 dark:text-emerald-400"
aria-hidden="true"
/>

{{-- Text --}}
<div>
<style>
.newsletter-gradient-text {
background-image: linear-gradient(
90deg,
var(--color-black) 0%,
var(--color-emerald-600) 35%,
var(--color-black) 70%
);
background-size: 200% 100%;
animation: newsletter-shine 2s linear infinite;
}
.dark .newsletter-gradient-text {
background-image: linear-gradient(
90deg,
var(--color-white) 0%,
var(--color-emerald-400) 35%,
var(--color-white) 70%
);
}
@keyframes newsletter-shine {
from {
background-position: 200% center;
}
to {
background-position: 0% center;
}
}
</style>
<div
class="newsletter-gradient-text bg-clip-text tracking-tight text-pretty text-transparent sm:text-center"
>
Celebrate
<b>SuperNative!</b>
Join the newsletter. Get
<b>10% off everything</b>
</div>
</div>
</div>

{{-- Arrow --}}
<div
class="transition duration-200 ease-in-out will-change-transform group-hover:translate-x-0.5"
>
<x-icons.right-arrow class="size-3 shrink-0" />
</div>
</button>
150 changes: 150 additions & 0 deletions resources/views/components/newsletter-modal.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
{{--
Newsletter signup modal. Opened from anywhere on the site by dispatching an
`open-newsletter-modal` window event, so triggers don't have to be nested
inside it. The form posts straight to Mailcoach, which then redirects to one
of our own `newsletter.*` pages depending on the outcome.
--}}
<div
x-data="{ open: false }"
@open-newsletter-modal.window="
open = true
$nextTick(() => $refs.email?.focus())
"
@keydown.escape.window="open = false"
>
{{-- Backdrop --}}
<div
x-show="open"
x-transition:enter="transition duration-300 ease-out"
x-transition:enter-start="opacity-0"
x-transition:enter-end="opacity-100"
x-transition:leave="transition duration-200 ease-in"
x-transition:leave-start="opacity-100"
x-transition:leave-end="opacity-0"
class="fixed inset-0 z-50 bg-black/50 backdrop-blur-xs"
x-cloak
></div>

<div
x-show="open"
x-transition:enter="transition duration-300 ease-out"
x-transition:enter-start="scale-95 opacity-0"
x-transition:enter-end="scale-100 opacity-100"
x-transition:leave="transition duration-200 ease-in"
x-transition:leave-start="scale-100 opacity-100"
x-transition:leave-end="scale-95 opacity-0"
class="fixed inset-0 z-50 flex items-center justify-center p-4"
role="dialog"
aria-modal="true"
aria-labelledby="newsletter-modal-heading"
x-cloak
>
<div
@click.away="open = false"
class="relative w-full max-w-md overflow-hidden rounded-2xl bg-white p-8 shadow-xl ring-1 ring-black/5 dark:bg-mirage dark:ring-white/10"
>
{{-- Decorative glow --}}
<div
class="pointer-events-none absolute -top-24 left-1/2 size-40 -translate-x-1/2 rounded-full bg-emerald-400/40 blur-3xl"
aria-hidden="true"
></div>

{{-- Close --}}
<button
type="button"
@click="open = false"
class="absolute top-4 right-4 rounded-lg p-2 text-gray-400 transition duration-200 hover:bg-gray-100 hover:text-gray-600 dark:hover:bg-white/5 dark:hover:text-gray-200"
>
<x-icons.xmark class="size-3" />
<span class="sr-only">Close</span>
</button>

<div class="text-center">
<x-icons.gift
class="mx-auto size-8 text-emerald-600 dark:text-emerald-400"
aria-hidden="true"
/>

<h2
id="newsletter-modal-heading"
class="mt-4 text-xl font-semibold"
>
Get 10% off
</h2>

<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
Join the NativePHP newsletter and we'll email you a 10%
discount code, along with the latest updates and news.
</p>
</div>

<form
method="post"
action="{{ config('services.mailcoach.newsletter_subscribe_url') }}"
class="mt-6 flex flex-col gap-3"
>
{{-- Honeypot: must be submitted empty to pass Mailcoach's bot check --}}
<div class="absolute -left-[9999px]">
<label
for="newsletter-{{ config('services.mailcoach.honeypot_field') }}"
>
Your pet
</label>
<input
type="text"
id="newsletter-{{ config('services.mailcoach.honeypot_field') }}"
name="{{ config('services.mailcoach.honeypot_field') }}"
tabindex="-1"
autocomplete="nope"
/>
</div>

<label
for="newsletter-email"
class="sr-only"
>
Email address
</label>
<input
x-ref="email"
type="email"
id="newsletter-email"
name="email"
placeholder="you@example.com"
autocomplete="email"
required
class="w-full rounded-xl border border-gray-300 bg-white px-4 py-3 text-sm text-gray-900 placeholder-gray-400 focus:border-emerald-500 focus:ring-emerald-500 dark:border-gray-700 dark:bg-gray-800 dark:text-white dark:placeholder-gray-500"
/>

{{-- Where Mailcoach sends people once it has handled the signup --}}
<input
type="hidden"
name="redirect_after_subscription_pending"
value="{{ route('newsletter.confirm') }}"
/>
<input
type="hidden"
name="redirect_after_subscribed"
value="{{ route('newsletter.subscribed') }}"
/>
<input
type="hidden"
name="redirect_after_already_subscribed"
value="{{ route('newsletter.already-subscribed') }}"
/>

<button
type="submit"
@click="window.fathom?.trackEvent('newsletter_modal_submit')"
class="rounded-xl bg-gray-900 px-6 py-3 text-sm font-semibold text-white transition duration-200 hover:bg-gray-800 dark:bg-white dark:text-gray-900 dark:hover:bg-gray-100"
>
Send me the code
</button>

<p class="text-center text-xs text-gray-400 dark:text-gray-500">
We'll send a confirmation email first. Unsubscribe any time.
</p>
</form>
</div>
</div>
</div>
79 changes: 79 additions & 0 deletions resources/views/components/newsletter-status.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
@props([
'title',
])

{{-- These pages are the tail end of a signup flow; they have nothing to index. --}}
@push('head')
<meta
name="robots"
content="noindex, nofollow"
/>
@endpush

<x-layout :title="$title">
<section
class="mx-auto flex w-full max-w-2xl flex-col items-center px-5 py-24 text-center md:py-32"
aria-labelledby="newsletter-status-heading"
>
{{-- Blurred circle - Decorative --}}
<div
class="absolute top-40 right-1/2 -z-30 h-60 w-60 translate-x-1/2 rounded-full blur-[150px] md:w-80 dark:bg-emerald-500/40"
aria-hidden="true"
></div>

<div
x-init="
() => {
motion.animate(
$el,
{
opacity: [0, 1],
y: [10, 0],
},
{
duration: 0.7,
ease: motion.circOut,
},
)
}
"
class="flex flex-col items-center opacity-0"
>
{{-- Icon --}}
<div
class="grid size-16 place-items-center rounded-2xl bg-emerald-50 ring-1 ring-black/5 dark:bg-emerald-950/50 dark:ring-white/10"
>
{{ $icon }}
</div>

{{-- Heading --}}
<h1
id="newsletter-status-heading"
class="mt-8 text-3xl font-extrabold text-balance sm:text-4xl"
>
{{ $title }}
</h1>

{{-- Message --}}
<div
class="mt-4 max-w-lg leading-relaxed text-pretty opacity-70 [&_p+p]:mt-3"
>
{{ $slot }}
</div>

{{-- Actions --}}
<div
class="mt-10 flex flex-col flex-wrap items-center gap-3 sm:flex-row sm:justify-center"
>
{{ $actions ?? '' }}

<a
href="{{ route('welcome') }}"
class="rounded-xl px-6 py-3 text-sm font-semibold ring-1 ring-black/10 transition duration-200 hover:bg-gray-50 dark:ring-white/15 dark:hover:bg-white/5"
>
Back to nativephp.com
</a>
</div>
</div>
</section>
</x-layout>
Loading