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
10 changes: 5 additions & 5 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- name: 🥟 Setup bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "1.3.8"
bun-version: '1.3.8'

- name: 📥 Download deps
run: bun install --frozen-lockfile
Expand All @@ -56,7 +56,7 @@ jobs:
- name: 🥟 Setup bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "1.3.8"
bun-version: '1.3.8'

- name: 📥 Download deps
run: bun install --frozen-lockfile
Expand All @@ -82,7 +82,7 @@ jobs:
- name: 🥟 Setup bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "1.3.8"
bun-version: '1.3.8'

- name: 📥 Download deps
run: bun install --frozen-lockfile
Expand All @@ -108,7 +108,7 @@ jobs:
- name: 🥟 Setup bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "1.3.8"
bun-version: '1.3.8'

- name: 📥 Download deps
run: bun install --frozen-lockfile
Expand Down Expand Up @@ -146,7 +146,7 @@ jobs:
- name: 🥟 Setup bun
uses: oven-sh/setup-bun@v1
with:
bun-version: "1.3.8"
bun-version: '1.3.8'

- name: 📥 Download deps
run: bun install --frozen-lockfile
Expand Down
22 changes: 11 additions & 11 deletions app/components/search-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,17 @@ export function SearchBar({
>
<div className="flex w-full items-center gap-2 sm:flex-1">
<div className="min-w-0 flex-1">
<Label htmlFor={id} className="sr-only">
Search
</Label>
<Input
type="search"
name="search"
id={id}
defaultValue={searchParams.get('search') ?? ''}
placeholder="Search"
className="w-full"
autoFocus={autoFocus}
<Label htmlFor={id} className="sr-only">
Search
</Label>
<Input
type="search"
name="search"
id={id}
defaultValue={searchParams.get('search') ?? ''}
placeholder="Search"
className="w-full"
autoFocus={autoFocus}
/>
</div>
<StatusButton
Expand Down
11 changes: 4 additions & 7 deletions app/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,17 @@ const buttonVariants = cva(
variant: {
default:
'bg-primary text-primary-foreground hover:bg-primary/90 shadow-sm',
brand:
'bg-[hsl(var(--palette-green-500))] text-[hsl(var(--palette-cream))] hover:bg-[hsl(var(--palette-green-700))] shadow-sm',
brand: 'bg-brand text-brand-foreground hover:bg-brand/90 shadow-sm',
'brand-soft':
'bg-[hsl(var(--palette-green-300))] text-[hsl(var(--palette-dark-navy))] hover:bg-[hsl(var(--palette-green-500))] hover:text-[hsl(var(--palette-cream))] shadow-sm',
warm:
'bg-[hsl(var(--palette-chestnut))] text-[hsl(var(--palette-cream))] hover:bg-[hsl(var(--palette-hot-fire-red))] shadow-sm',
'bg-brand-soft text-brand-soft-foreground hover:bg-brand hover:text-brand-foreground shadow-sm',
warm: 'bg-warm text-warm-foreground hover:bg-warm/90 shadow-sm',
destructive:
'bg-destructive text-destructive-foreground hover:bg-destructive/90 shadow-sm',
outline: 'border-border bg-card text-foreground hover:bg-muted border',
secondary:
'border-border text-foreground hover:bg-muted border bg-transparent',
ghost: 'text-foreground hover:bg-muted',
'ghost-inverse':
'text-[hsl(var(--palette-cream))] hover:bg-[hsl(var(--palette-cream))/0.15]',
'ghost-inverse': 'text-inverse hover:bg-inverse/15',
link: 'text-primary underline-offset-4 hover:underline',
},
size: {
Expand Down
2 changes: 1 addition & 1 deletion app/routes/_app+/_auth+/verify.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export default function VerifyRoute() {
errors={fields[codeQueryParam].errors}
groupClassName="gap-2 sm:gap-3"
showSeparator={false}
slotClassName="h-11 w-11 rounded-full bg-white text-base font-semibold shadow-none dark:bg-[hsl(var(--palette-navy))] sm:h-14 sm:w-14 sm:text-lg"
slotClassName="bg-card text-foreground h-11 w-11 rounded-full text-base font-semibold shadow-none sm:h-14 sm:w-14 sm:text-lg"
/>
<div className="text-body-sm text-muted-foreground flex flex-wrap items-center gap-1">
<span>No text after 5 minutes?</span>
Expand Down
43 changes: 17 additions & 26 deletions app/routes/_app+/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useRef, useState, type CSSProperties } from 'react'
import { useRef, useState } from 'react'
import {
Form,
Link,
Expand Down Expand Up @@ -67,18 +67,8 @@ export default function Layout() {
const data = useLoaderData<typeof loader>()
const user = useOptionalUser()
const requestInfo = useRequestInfo()
const isRecipientsRoute = requestInfo.path.startsWith('/recipients')
const recipientsTheme = isRecipientsRoute
? ({
'--background': '0 0% 100%',
'--card': '0 0% 100%',
} as CSSProperties)
: undefined
return (
<div
className="bg-background flex h-screen flex-col justify-between"
style={recipientsTheme}
>
<div className="bg-background flex h-screen flex-col justify-between">
<header className="border-border border-b">
<div className="container py-5 md:py-6">
<nav className="flex flex-wrap items-center justify-between gap-4 sm:flex-nowrap md:gap-8">
Expand Down Expand Up @@ -123,35 +113,41 @@ export default function Layout() {
<nav>
<ul className="flex list-none flex-col gap-2 sm:flex-row sm:flex-wrap sm:gap-4">
<li>
<Link to="/about" className="text-gray-600 hover:text-gray-900">
<Link
to="/about"
className="text-muted-foreground hover:text-foreground"
>
About
</Link>
</li>
<li>
<Link
to="/privacy"
className="text-gray-600 hover:text-gray-900"
className="text-muted-foreground hover:text-foreground"
>
Privacy
</Link>
</li>
<li>
<Link to="/tos" className="text-gray-600 hover:text-gray-900">
<Link
to="/tos"
className="text-muted-foreground hover:text-foreground"
>
Terms of Service
</Link>
</li>
<li>
<Link
to="/support"
className="text-gray-600 hover:text-gray-900"
className="text-muted-foreground hover:text-foreground"
>
Support
</Link>
</li>
<li>
<Link
to="/contact"
className="text-gray-600 hover:text-gray-900"
className="text-muted-foreground hover:text-foreground"
>
Contact
</Link>
Expand Down Expand Up @@ -266,7 +262,7 @@ function MobileMenu() {
<div className="fixed inset-0 z-50 flex justify-center">
<button
type="button"
className="absolute inset-0 h-full w-full bg-black/20"
className="bg-overlay/30 absolute inset-0 h-full w-full"
onClick={() => setOpen(false)}
aria-label="Close menu"
/>
Expand All @@ -286,12 +282,7 @@ function MobileMenu() {
<Icon name="close" size="lg" aria-hidden="true" />
</Button>
</div>
<Button
asChild
size="lg"
variant="warm"
className="mt-6 w-full"
>
<Button asChild size="lg" variant="warm" className="mt-6 w-full">
<Link to="/login" onClick={() => setOpen(false)}>
<Icon name="star" size="sm" aria-hidden="true">
Start 14-day FREE Trial
Expand All @@ -307,7 +298,7 @@ function MobileMenu() {
<Icon
name="log in"
size="sm"
className="text-[hsl(var(--palette-cloud))]"
className="text-muted-foreground"
aria-hidden="true"
/>
Log In
Expand All @@ -323,7 +314,7 @@ function MobileMenu() {
<Icon
name={themeIcon}
size="sm"
className="text-[hsl(var(--palette-cloud))]"
className="text-muted-foreground"
aria-hidden="true"
/>
{themeLabel}
Expand Down
43 changes: 18 additions & 25 deletions app/routes/_app+/_marketing+/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@ export default function Index() {
<section className="container grid gap-10 lg:grid-cols-[0.95fr_1.05fr] lg:items-center">
<div className="order-1 flex justify-center lg:order-2">
<div className="relative w-full max-w-xs sm:max-w-sm">
<div className="absolute top-1/2 left-1/2 h-[260px] w-[260px] -translate-x-1/2 -translate-y-1/2 rounded-full bg-[hsl(var(--palette-baby-blue))] sm:h-[320px] sm:w-[320px]" />
<div className="bg-hero-orb absolute top-1/2 left-1/2 h-[260px] w-[260px] -translate-x-1/2 -translate-y-1/2 rounded-full sm:h-[320px] sm:w-[320px]" />
<Icon
name="star"
size="lg"
aria-hidden="true"
className="absolute top-2 left-2 text-[hsl(var(--palette-orange))]"
className="text-hero-sparkle absolute top-2 left-2"
/>
<Icon
name="star"
size="md"
aria-hidden="true"
className="absolute top-16 left-12 text-[hsl(var(--palette-orange))]"
className="text-hero-sparkle absolute top-16 left-12"
/>
<div className="absolute top-24 left-4 h-6 w-10 rounded-full bg-[hsl(var(--palette-orange))]" />
<div className="absolute bottom-6 left-6 h-12 w-12 rounded-[22px] bg-[hsl(var(--palette-orange))]" />
<div className="absolute top-1/2 -right-2 flex h-12 w-12 -translate-y-1/2 items-center justify-center rounded-full bg-[hsl(var(--palette-green-500))] text-[hsl(var(--palette-cream))] shadow-lg">
<div className="bg-hero-sparkle absolute top-24 left-4 h-6 w-10 rounded-full" />
<div className="bg-hero-sparkle absolute bottom-6 left-6 h-12 w-12 rounded-[22px]" />
<div className="bg-brand text-brand-foreground absolute top-1/2 -right-2 flex h-12 w-12 -translate-y-1/2 items-center justify-center rounded-full shadow-lg">
<Icon name="message" size="sm" aria-hidden="true" />
</div>
<img
Expand Down Expand Up @@ -81,17 +81,17 @@ export default function Index() {
</section>

<section className="container mt-16">
<div className="relative overflow-hidden rounded-[48px] bg-[hsl(var(--palette-green-700))] px-6 py-12 text-[hsl(var(--palette-cream))] shadow-sm dark:bg-[hsl(var(--palette-green-900))]">
<div className="absolute -top-6 -left-6 hidden h-20 w-20 rounded-full bg-[hsl(var(--palette-sunny))] opacity-80 md:block" />
<div className="absolute right-10 -bottom-6 hidden h-24 w-24 rounded-[32px] bg-[hsl(var(--palette-orange))] opacity-70 md:block" />
<div className="bg-marketing-feature text-marketing-feature-foreground relative overflow-hidden rounded-[48px] px-6 py-12 shadow-sm">
<div className="bg-marketing-feature-accent absolute -top-6 -left-6 hidden h-20 w-20 rounded-full opacity-80 md:block" />
<div className="bg-marketing-feature-accent-secondary absolute right-10 -bottom-6 hidden h-24 w-24 rounded-[32px] opacity-70 md:block" />
<div className="mx-auto max-w-3xl text-center">
<p className="text-xs font-semibold tracking-[0.3em] text-[hsl(var(--palette-green-100))] uppercase">
<p className="text-marketing-feature-muted text-xs font-semibold tracking-[0.3em] uppercase">
Messages written by you
</p>
<h2 className="mt-3 text-3xl font-bold md:text-4xl">
Messages written by you... Not by AI.
</h2>
<p className="mx-auto mt-4 max-w-2xl text-base text-[hsl(var(--palette-green-100))]">
<p className="text-marketing-feature-muted mx-auto mt-4 max-w-2xl text-base">
Our platform schedules and delivers personal, heartfelt messages
on your schedule, so you can stay connected without losing your
voice.
Expand Down Expand Up @@ -150,7 +150,7 @@ export default function Index() {
key={step.title}
className="border-border bg-card rounded-[28px] border p-6 shadow-sm"
>
<p className="text-3xl font-bold text-[hsl(var(--palette-chestnut))]">
<p className="text-marketing-step-index text-3xl font-bold">
{String(index + 1).padStart(2, '0')}
</p>
<h3 className="text-foreground mt-2 text-xl font-bold">
Expand Down Expand Up @@ -186,9 +186,7 @@ export default function Index() {
1 message per day
</p>
</div>
<p className="text-2xl font-bold text-[hsl(var(--palette-cloud))]">
$4.99
</p>
<p className="text-price-basic text-2xl font-bold">$4.99</p>
</div>
<div className="mt-6">
<Button asChild variant="secondary">
Expand All @@ -204,9 +202,7 @@ export default function Index() {
10 messages per day
</p>
</div>
<p className="text-2xl font-bold text-[hsl(var(--palette-chestnut))]">
$14.99
</p>
<p className="text-price-premium text-2xl font-bold">$14.99</p>
</div>
<div className="mt-6">
<Button asChild>
Expand All @@ -219,24 +215,21 @@ export default function Index() {
</section>

<section className="container py-16">
<div className="rounded-[32px] bg-[hsl(var(--palette-dust-pink))] px-8 py-12 text-[hsl(var(--palette-chocolate))]">
<div className="bg-marketing-cta text-marketing-cta-foreground rounded-[32px] px-8 py-12">
<div className="flex flex-col gap-6 md:flex-row md:items-center md:justify-between">
<div className="space-y-3">
<p className="text-xs font-semibold tracking-[0.3em] text-[hsl(var(--palette-chestnut))] uppercase">
<p className="text-marketing-cta-accent text-xs font-semibold tracking-[0.3em] uppercase">
Ready to start
</p>
<h2 className="text-3xl font-bold md:text-4xl">
Create your account today and get 2 weeks for free.
</h2>
<p className="text-body-sm text-[hsl(var(--palette-chestnut))]">
<p className="text-marketing-cta-accent text-body-sm">
No credit card required to get started.
</p>
</div>
<div className="flex flex-col gap-3 sm:flex-row">
<Button
asChild
variant="warm"
>
<Button asChild variant="warm">
<Link to="/login">Get started</Link>
</Button>
</div>
Expand Down
16 changes: 8 additions & 8 deletions app/routes/_app+/recipients+/$recipientId.index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -605,7 +605,7 @@ export default function RecipientRoute() {
{hasAnyMessages ? (
<div
ref={setScrollContainer}
className="max-h-[65vh] overflow-y-auto bg-[linear-gradient(90deg,_hsl(var(--palette-cream)),_hsl(var(--palette-beige))_45%,_hsl(0_0%_100%)_100%)] px-4 py-5 sm:px-5 sm:py-6"
className="thread-gradient max-h-[65vh] overflow-y-auto px-4 py-5 sm:px-5 sm:py-6"
>
{hasPastMessages || pastNextCursor ? (
<div className="text-muted-foreground flex flex-col items-center gap-2 text-xs font-semibold tracking-[0.2em] uppercase">
Expand All @@ -615,7 +615,7 @@ export default function RecipientRoute() {
<ul className="flex flex-col gap-4 sm:gap-5">
{pastMessagesForDisplay.map((m) => (
<li key={m.id} className="flex flex-col items-end gap-1">
<div className="max-w-[75%] rounded-[24px] bg-[hsl(var(--palette-green-500))] px-4 py-3 text-sm leading-relaxed text-[hsl(var(--palette-cream))] shadow-sm sm:max-w-[65%] sm:px-5 sm:py-4">
<div className="bg-message-bubble text-message-bubble-foreground max-w-[75%] rounded-[24px] px-4 py-3 text-sm leading-relaxed shadow-sm sm:max-w-[65%] sm:px-5 sm:py-4">
<p className="whitespace-pre-wrap">{m.content}</p>
</div>
<time
Expand All @@ -632,7 +632,7 @@ export default function RecipientRoute() {
</ul>
</div>
) : (
<div className="bg-[linear-gradient(90deg,_hsl(var(--palette-cream)),_hsl(var(--palette-beige))_45%,_hsl(0_0%_100%)_100%)] px-4 py-10 text-center text-sm sm:px-5 sm:py-12">
<div className="thread-gradient px-4 py-10 text-center text-sm sm:px-5 sm:py-12">
<p className="text-muted-foreground">{emptyThreadMessage}</p>
<Link
to="new"
Expand All @@ -647,7 +647,7 @@ export default function RecipientRoute() {
<newMessageFetcher.Form
method="POST"
action="new"
className="border-border/40 rounded-full border bg-white p-2 shadow-sm transition focus-within:rounded-[28px] focus-within:border-border/60 focus-within:shadow-md"
className="border-border/40 bg-card focus-within:border-border/60 rounded-full border p-2 shadow-sm transition focus-within:rounded-[28px] focus-within:shadow-md"
>
<label htmlFor="new-message" className="sr-only">
Add a new message
Expand Down Expand Up @@ -706,7 +706,7 @@ function MessageForms({ message }: { message: FutureMessage }) {
},
shouldRevalidate: 'onBlur',
})
const cardTone = 'bg-[hsl(var(--palette-blues))]'
const cardTone = 'bg-message-card'
const scheduleLabel = message.sendAtDisplay
? `Scheduled for ${message.sendAtDisplay}`
: 'Scheduled message'
Expand Down Expand Up @@ -762,9 +762,9 @@ function MessageForms({ message }: { message: FutureMessage }) {
return (
<li className="flex flex-col items-end gap-2">
<div
className={`max-w-[75%] rounded-[24px] px-4 py-3 text-[hsl(var(--palette-cream))] shadow-sm sm:max-w-[65%] sm:px-5 sm:py-4 ${cardTone}`}
className={`text-message-card-foreground max-w-[75%] rounded-[24px] px-4 py-3 shadow-sm sm:max-w-[65%] sm:px-5 sm:py-4 ${cardTone}`}
>
<div className="flex items-start justify-between gap-4 text-[0.7rem] font-semibold tracking-[0.2em] text-[hsl(var(--palette-cream))] uppercase">
<div className="text-message-card-foreground flex items-start justify-between gap-4 text-[0.7rem] font-semibold tracking-[0.2em] uppercase">
<div className="flex items-center gap-2">
<Icon name="clock" size="sm" />
<span>{scheduleLabel}</span>
Expand Down Expand Up @@ -846,7 +846,7 @@ function MessageForms({ message }: { message: FutureMessage }) {
setCurrentContent(event.currentTarget.value)
}}
ref={textareaRef}
className="mt-2 w-full resize-none bg-transparent text-sm leading-relaxed text-[hsl(var(--palette-cream))] placeholder:text-[hsl(var(--palette-cream))]/80 focus-visible:outline-none"
className="text-message-card-foreground placeholder:text-message-card-foreground/80 mt-2 w-full resize-none bg-transparent text-sm leading-relaxed focus-visible:outline-none"
rows={2}
/>
</updateContentFetcher.Form>
Expand Down
Loading
Loading