Skip to content
This repository was archived by the owner on Sep 18, 2024. It is now read-only.

chore: implement landing page changes #116

Merged
merged 14 commits into from
May 13, 2024
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
12 changes: 6 additions & 6 deletions packages/studio-ts/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import logoPhobiaLight from '@/images/clients/phobia/logo-light.svg'
import logoUnseal from '@/images/clients/unseal/logo-light.svg'
import imageLaptop from '@/images/laptop.jpg'
import { type CaseStudy, type MDXEntry, loadCaseStudies } from '@/lib/mdx'
import { WaitlistForm } from '@/components/WaitlistForm'

const clients = [
['Phobia', logoPhobiaLight],
Expand Down Expand Up @@ -185,13 +186,12 @@ export default async function Home() {
<Container className="mt-24 sm:mt-32 md:mt-56">
<FadeIn className="max-w-3xl">
<h1 className="font-display text-5xl font-medium tracking-tight text-neutral-950 [text-wrap:balance] sm:text-7xl">
Award-winning development studio based in Denmark.
The open source Assistant Platform
</h1>
<p className="mt-6 text-xl text-neutral-600">
We are a development studio working at the intersection of design
and technology. It’s a really busy intersection though — a lot of
our staff have been involved in hit and runs.
</p>
<p className="mt-6 text-xl text-neutral-600">Join the waiting list</p>
<div>
<WaitlistForm />
</div>
</FadeIn>
</Container>

Expand Down
37 changes: 37 additions & 0 deletions packages/studio-ts/src/app/server.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use server'

export type FormState = {
message: string
submitted: boolean
}

export const handleWaitlistSubmit = async (
prevState: FormState,
formData: FormData,
) => {
const url = process.env.NEXT_GOOGLE_SHEETS_API!
let rawFormData = { email: formData.get('email') }

try {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(rawFormData),
})

if (response.ok) {
return { message: 'Email address sent successfully!', submitted: true }
} else {
console.error(
'Failed to send email address. Status code:',
response.status,
)
}
} catch (error) {
return { message: 'Email address not sent', submitted: false }
}

return { message: 'Email address not sent', submitted: false }
}
46 changes: 0 additions & 46 deletions packages/studio-ts/src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,60 +65,14 @@ function Navigation() {
)
}

function ArrowIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 16 6" aria-hidden="true" {...props}>
<path
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
d="M16 3 10 .5v2H0v1h10v2L16 3Z"
/>
</svg>
)
}

function NewsletterForm() {
return (
<form className="max-w-sm">
<h2 className="font-display text-sm font-semibold tracking-wider text-neutral-950">
Sign up for our newsletter
</h2>
<p className="mt-4 text-sm text-neutral-700">
Subscribe to get the latest design news, articles, resources and
inspiration.
</p>
<div className="relative mt-6">
<input
type="email"
placeholder="Email address"
autoComplete="email"
aria-label="Email address"
className="block w-full rounded-2xl border border-neutral-300 bg-transparent py-4 pl-6 pr-20 text-base/6 text-neutral-950 ring-4 ring-transparent transition placeholder:text-neutral-500 focus:border-neutral-950 focus:outline-none focus:ring-neutral-950/5"
/>
<div className="absolute inset-y-1 right-1 flex justify-end">
<button
type="submit"
aria-label="Submit"
className="flex aspect-square h-full items-center justify-center rounded-xl bg-neutral-950 text-white transition hover:bg-neutral-800"
>
<ArrowIcon className="w-4" />
</button>
</div>
</div>
</form>
)
}

export function Footer() {
return (
<Container as="footer" className="mt-24 w-full sm:mt-32 lg:mt-40">
<FadeIn>
<div className="grid grid-cols-1 gap-x-8 gap-y-16 lg:grid-cols-2">
<Navigation />
<div className="flex lg:justify-end">
<NewsletterForm />
</div>
</div>
<div className="mb-20 mt-24 flex flex-wrap items-end justify-between gap-x-6 gap-y-4 border-t border-neutral-950/10 pt-12">
<Link href="/" aria-label="Home">
Expand Down
8 changes: 4 additions & 4 deletions packages/studio-ts/src/components/RootLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ function Header({
/>
</Link>
<div className="flex items-center gap-x-8">
<Button href="/contact" invert={invert}>
Contact us
<Button href="https://github.com/AkeruAI/akeru" invert={invert}>
Star on Github!
</Button>
<button
{/* <button
ref={toggleRef}
type="button"
onClick={onToggle}
Expand All @@ -104,7 +104,7 @@ function Header({
: 'fill-neutral-950 group-hover:fill-neutral-700',
)}
/>
</button>
</button> */}
</div>
</div>
</Container>
Expand Down
79 changes: 79 additions & 0 deletions packages/studio-ts/src/components/WaitlistForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
"use client"
import { FormState, handleWaitlistSubmit } from '@/app/server'
import { useFormState, useFormStatus } from 'react-dom'

const initialState: FormState = {
message: '',
submitted: false,
}

function ArrowIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg viewBox="0 0 16 6" aria-hidden="true" {...props}>
<path
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
d="M16 3 10 .5v2H0v1h10v2L16 3Z"
/>
</svg>
)
}

function CheckMarkIcon(props: React.ComponentPropsWithoutRef<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
fillRule="evenodd"
clipRule="evenodd"
aria-hidden="true"
{...props}
viewBox="0 0 24 24"
>
<path d="M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z" />
</svg>
)
}

export function WaitlistForm() {
const [state, formAction] = useFormState(handleWaitlistSubmit, initialState)

return (
<form className="max-w-sm" action={formAction}>
<div className="relative mt-6">
<input
type="email"
placeholder="Email address"
autoComplete="email"
required
name={'email'}
aria-label="Email address"
className="block w-full rounded-2xl border border-neutral-300 bg-transparent py-4 pl-6 pr-20 text-base/6 text-neutral-950 ring-4 ring-transparent transition placeholder:text-neutral-500 focus:border-neutral-950 focus:outline-none focus:ring-neutral-950/5"
/>
<div className="absolute inset-y-1 right-1 flex justify-end">
<FormIconDisplay submitted={state?.submitted} />
</div>
</div>
</form>
)
}

function FormIconDisplay({ submitted }: { submitted: boolean | undefined }) {
const { pending } = useFormStatus()

return (
<button
type="submit"
aria-label="Submit"
disabled={pending}
className="flex aspect-square h-full items-center justify-center rounded-xl bg-neutral-950 text-white transition hover:bg-neutral-800"
>
{submitted ? (
<CheckMarkIcon className="w-4" />
) : (
<ArrowIcon className="w-4" />
)}
</button>
)
}