Subscribe

Installation

Add the following Soul components

The subscribe component uses the inline-email-form component. Make sure you have added it to your project.

Install the following dependencies

npm install clsx

Copy and paste the following code into your project

sections/subscribe/index.tsx

import { SubmissionResult } from '@conform-to/react';import { clsx } from 'clsx';import Image from 'next/image';import { InlineEmailForm } from '@/vibes/soul/sections/inline-email-form';type Action<State, Payload> = (state: Awaited<State>, payload: Payload) => State | Promise<State>;type SubscribeAction = Action<  { lastResult: SubmissionResult | null; successMessage?: string },  FormData>;export interface SubscribeProps {  action: SubscribeAction;  image?: { src: string; alt: string };  title: string;  description?: string;  placeholder?: string;}/** * This component supports various CSS variables for theming. Here's a comprehensive list, along * with their default values: * * ```css * :root { *   --subscribe-font-family: var(--font-family-body); *   --subscribe-title-font-family: var(--font-family-heading); *   --subscribe-background: color-mix(in oklab, hsl(var(--primary)), black 75%); *   --subscribe-title: color-mix(in oklab, hsl(var(--primary)), white 75%); *   --subscribe-description: color-mix(in oklab, hsl(var(--primary)), white 75%); * } * ``` */export function Subscribe({ action, image, title, description, placeholder }: SubscribeProps) {  return (    <section className="bg-[var(--subscribe-background,color-mix(in_oklab,hsl(var(--primary)),black_75%))] font-[family-name:var(--subscribe-font-family,var(--font-family-body))] @container">      <div className="flex flex-col items-start @4xl:flex-row @4xl:items-stretch">        {image && (          <div className="relative min-h-96 w-full bg-primary/10 @4xl:flex-1">            <Image              alt={image.alt}              className="object-cover"              fill              sizes="(min-width: 56rem) 50vw, 100vw"              src={image.src}            />          </div>        )}        <div className="w-full flex-1">          <div            className={clsx(              'flex w-full flex-col gap-10 px-4 py-10 @xl:px-6 @xl:py-14 @4xl:gap-16 @4xl:px-8 @4xl:py-20',              Boolean(image) ? '@4xl:max-w-4xl' : 'mx-auto max-w-screen-2xl @4xl:flex-row',            )}          >            <header className="flex-1">              <h2 className="mb-4 font-[family-name:var(--subscribe-title-font-family,var(--font-family-heading))] text-2xl font-medium leading-none text-[var(--subscribe-title,color-mix(in_oklab,hsl(var(--primary)),white_75%))] @xl:text-3xl @4xl:text-4xl">                {title}              </h2>              <p className="text-[var(--subscribe-description,color-mix(in_oklab,hsl(var(--primary)),white_75%))] opacity-75">                {description}              </p>            </header>            <InlineEmailForm action={action} className="flex-1" placeholder={placeholder} />          </div>        </div>      </div>    </section>  );}

Usage

function Usage() {  return (      <Subscribe          action={action}          description="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor."          image={image}          title="Sign up for our newsletter"      />  );} const image = {  src: 'https://rstr.in/monogram/vibes/m12FEyfnuDl',  alt: 'Lady with plant',};async function action(   _lastResult: { lastResult: SubmissionResult | null },  formData: FormData,) {  'use server';  const submission = parseWithZod(formData, { schema });  if (submission.status !== 'success') {      return { lastResult: submission.reply({ formErrors: ['Boom!'] }) };  }  // Simulate subscribing a user  await new Promise((resolve) => setTimeout(resolve, 1000));  return { lastResult: submission.reply(), successMessage: 'Subscribed!' };}

API Reference

SubscribeProps

PropTypeDefault
action*
SubscribeAction
image
Image
title*
string
description
string
placeholder
string

ForgotPasswordAction

type Action<State, Payload> = (state: Awaited<State>, payload: Payload) => State | Promise<State>;type SubscribeAction = Action<  { lastResult: SubmissionResult | null; successMessage?: string },  FormData>;

This component uses Confom to handle form submissions. Refer to the Conform docs for more details.

Here's an example of an action function that does validation and simulates subscribe a user:

async function action(_lastResult: { lastResult: SubmissionResult | null }, formData: FormData) {  'use server';  const submission = parseWithZod(formData, { schema });  if (submission.status !== 'success') {    return { lastResult: submission.reply({ formErrors: ['Boom!'] }) };  }  // Simulate subscribing a user  await new Promise((resolve) => setTimeout(resolve, 1000));  return { lastResult: submission.reply(), successMessage: 'Subscribed!' };}

Image

PropTypeDefault
src*
string
alt*
string

CSS Variables

This component supports various CSS variables for theming. Here's a comprehensive list.

:root {  --subscribe-font-family: var(--font-family-body);  --subscribe-title-font-family: var(--font-family-heading);  --subscribe-background: color-mix(in oklab, hsl(var(--primary)), black 75%);  --subscribe-title: color-mix(in oklab, hsl(var(--primary)), white 75%);  --subscribe-description: color-mix(in oklab, hsl(var(--primary)), white 75%);}