diff --git a/app/routes/_app+/recipients+/index.tsx b/app/routes/_app+/recipients+/index.tsx
index 9bb41968..576c2341 100644
--- a/app/routes/_app+/recipients+/index.tsx
+++ b/app/routes/_app+/recipients+/index.tsx
@@ -18,7 +18,7 @@ export default function RecipientsIndexRoute() {
return (
{showTrialBanner ? (
-
+
Upgrade to text unlimited loved ones!{' '}
Start your free trial
@@ -26,7 +26,7 @@ export default function RecipientsIndexRoute() {
) : null}
{showUpgradeBanner ? (
-
+
Upgrade to Premium to text more loved ones.{' '}
Upgrade to Premium
@@ -70,9 +70,7 @@ export default function RecipientsIndexRoute() {
const messageText = `${messageCount} ${messageLabel}`
const messagePreparedText = `${messageText} prepared`
const messageTone =
- messageCount === 0
- ? 'text-[hsl(var(--palette-orange))]'
- : 'text-muted-foreground'
+ messageCount === 0 ? 'text-warning' : 'text-muted-foreground'
const scheduleTone = recipient.disabled
? 'text-muted-foreground'
: recipient.cronError
@@ -122,7 +120,7 @@ export default function RecipientsIndexRoute() {
{messageText}
{messageCount === 0 ? (
-
+
) : null}
diff --git a/app/routes/_app+/settings.profile+/subscription.tsx b/app/routes/_app+/settings.profile+/subscription.tsx
index 2627974f..16da79ee 100644
--- a/app/routes/_app+/settings.profile+/subscription.tsx
+++ b/app/routes/_app+/settings.profile+/subscription.tsx
@@ -65,9 +65,7 @@ export default function Subscribe() {
1 message per day
-
- $4.99
-
+
$4.99
{isBasic || isPremium ? (
@@ -89,9 +87,7 @@ export default function Subscribe() {
10 messages per day
-
- $14.99
-
+
$14.99
{isPremium ? (
diff --git a/app/styles/tailwind.css b/app/styles/tailwind.css
index 63a83478..b537ad77 100644
--- a/app/styles/tailwind.css
+++ b/app/styles/tailwind.css
@@ -67,6 +67,50 @@
--ring: var(--palette-green-300);
+ --overlay: 0 0% 0%;
+ --inverse: var(--palette-cream);
+
+ --brand: var(--palette-green-500);
+ --brand-foreground: var(--palette-cream);
+ --brand-soft: var(--palette-green-300);
+ --brand-soft-foreground: var(--palette-dark-navy);
+ --warm: var(--palette-chestnut);
+ --warm-foreground: var(--palette-cream);
+
+ --warning: var(--palette-orange);
+ --warning-foreground: var(--palette-dark-navy);
+
+ --banner-trial: var(--palette-sunny);
+ --banner-trial-foreground: var(--palette-dark-navy);
+ --banner-upgrade: var(--palette-green-300);
+ --banner-upgrade-foreground: var(--palette-dark-navy);
+
+ --price-basic: var(--palette-cloud);
+ --price-premium: var(--palette-chestnut);
+
+ --hero-orb: var(--palette-baby-blue);
+ --hero-sparkle: var(--palette-orange);
+
+ --marketing-feature: var(--palette-green-700);
+ --marketing-feature-foreground: var(--palette-cream);
+ --marketing-feature-muted: var(--palette-green-100);
+ --marketing-feature-accent: var(--palette-sunny);
+ --marketing-feature-accent-secondary: var(--palette-orange);
+ --marketing-step-index: var(--palette-chestnut);
+
+ --marketing-cta: var(--palette-dust-pink);
+ --marketing-cta-foreground: var(--palette-chocolate);
+ --marketing-cta-accent: var(--palette-chestnut);
+
+ --message-bubble: var(--palette-green-500);
+ --message-bubble-foreground: var(--palette-cream);
+ --message-card: var(--palette-blues);
+ --message-card-foreground: var(--palette-cream);
+
+ --thread-gradient-start: var(--palette-cream);
+ --thread-gradient-mid: var(--palette-beige);
+ --thread-gradient-end: 0 0% 100%;
+
--radius: 0.5rem;
}
@@ -106,6 +150,50 @@
--destructive-foreground: var(--palette-cream);
--ring: var(--palette-green-300);
+
+ --overlay: 0 0% 0%;
+ --inverse: var(--palette-cream);
+
+ --brand: var(--palette-green-300);
+ --brand-foreground: var(--palette-dark-navy);
+ --brand-soft: var(--palette-green-700);
+ --brand-soft-foreground: var(--palette-cream);
+ --warm: var(--palette-orange);
+ --warm-foreground: var(--palette-dark-navy);
+
+ --warning: var(--palette-sunny);
+ --warning-foreground: var(--palette-dark-navy);
+
+ --banner-trial: var(--palette-orange);
+ --banner-trial-foreground: var(--palette-dark-navy);
+ --banner-upgrade: var(--palette-green-500);
+ --banner-upgrade-foreground: var(--palette-cream);
+
+ --price-basic: var(--palette-sunny);
+ --price-premium: var(--palette-rose-pink);
+
+ --hero-orb: var(--palette-navy);
+ --hero-sparkle: var(--palette-sunny);
+
+ --marketing-feature: var(--palette-green-900);
+ --marketing-feature-foreground: var(--palette-cream);
+ --marketing-feature-muted: var(--palette-green-300);
+ --marketing-feature-accent: var(--palette-sunny);
+ --marketing-feature-accent-secondary: var(--palette-orange);
+ --marketing-step-index: var(--palette-sunny);
+
+ --marketing-cta: var(--palette-navy);
+ --marketing-cta-foreground: var(--palette-cream);
+ --marketing-cta-accent: var(--palette-sunny);
+
+ --message-bubble: var(--palette-green-500);
+ --message-bubble-foreground: var(--palette-cream);
+ --message-card: var(--palette-blues);
+ --message-card-foreground: var(--palette-cream);
+
+ --thread-gradient-start: var(--palette-dark-navy);
+ --thread-gradient-mid: var(--palette-navy);
+ --thread-gradient-end: var(--palette-storm-grey);
}
@theme inline {
@@ -137,6 +225,41 @@
--color-destructive-foreground: hsl(var(--destructive-foreground));
--color-ring: hsl(var(--ring));
--color-ring-invalid: hsl(var(--foreground-destructive));
+ --color-overlay: hsl(var(--overlay));
+ --color-inverse: hsl(var(--inverse));
+ --color-brand: hsl(var(--brand));
+ --color-brand-foreground: hsl(var(--brand-foreground));
+ --color-brand-soft: hsl(var(--brand-soft));
+ --color-brand-soft-foreground: hsl(var(--brand-soft-foreground));
+ --color-warm: hsl(var(--warm));
+ --color-warm-foreground: hsl(var(--warm-foreground));
+ --color-warning: hsl(var(--warning));
+ --color-warning-foreground: hsl(var(--warning-foreground));
+ --color-banner-trial: hsl(var(--banner-trial));
+ --color-banner-trial-foreground: hsl(var(--banner-trial-foreground));
+ --color-banner-upgrade: hsl(var(--banner-upgrade));
+ --color-banner-upgrade-foreground: hsl(var(--banner-upgrade-foreground));
+ --color-price-basic: hsl(var(--price-basic));
+ --color-price-premium: hsl(var(--price-premium));
+ --color-hero-orb: hsl(var(--hero-orb));
+ --color-hero-sparkle: hsl(var(--hero-sparkle));
+ --color-marketing-feature: hsl(var(--marketing-feature));
+ --color-marketing-feature-foreground: hsl(
+ var(--marketing-feature-foreground)
+ );
+ --color-marketing-feature-muted: hsl(var(--marketing-feature-muted));
+ --color-marketing-feature-accent: hsl(var(--marketing-feature-accent));
+ --color-marketing-feature-accent-secondary: hsl(
+ var(--marketing-feature-accent-secondary)
+ );
+ --color-marketing-step-index: hsl(var(--marketing-step-index));
+ --color-marketing-cta: hsl(var(--marketing-cta));
+ --color-marketing-cta-foreground: hsl(var(--marketing-cta-foreground));
+ --color-marketing-cta-accent: hsl(var(--marketing-cta-accent));
+ --color-message-bubble: hsl(var(--message-bubble));
+ --color-message-bubble-foreground: hsl(var(--message-bubble-foreground));
+ --color-message-card: hsl(var(--message-card));
+ --color-message-card-foreground: hsl(var(--message-card-foreground));
}
@theme {
@@ -208,6 +331,17 @@
}
}
+@layer utilities {
+ .thread-gradient {
+ background-image: linear-gradient(
+ 90deg,
+ hsl(var(--thread-gradient-start)),
+ hsl(var(--thread-gradient-mid)) 45%,
+ hsl(var(--thread-gradient-end)) 100%
+ );
+ }
+}
+
@layer base {
*,
::after,
diff --git a/app/utils/cron-runner.server.ts b/app/utils/cron-runner.server.ts
index ae2076a2..783606ae 100644
--- a/app/utils/cron-runner.server.ts
+++ b/app/utils/cron-runner.server.ts
@@ -3,6 +3,7 @@ import {
clearIntervalAsync,
setIntervalAsync,
} from 'set-interval-async/dynamic'
+import { getScheduleWindow } from './cron.server.ts'
import { prisma } from './db.server.ts'
import { getrecipientsforcron } from './prisma-generated.server/sql.ts'
import {
@@ -10,7 +11,6 @@ import {
PREV_SCHEDULE_SENTINEL_DATE,
} from './schedule-constants.server.ts'
import { sendText, sendTextToRecipient } from './text.server.ts'
-import { getScheduleWindow } from './cron.server.ts'
const cronIntervalRef = remember<{
current: ReturnType | null
diff --git a/app/utils/cron.server.test.ts b/app/utils/cron.server.test.ts
index fe84610b..d09d134f 100644
--- a/app/utils/cron.server.test.ts
+++ b/app/utils/cron.server.test.ts
@@ -2,8 +2,8 @@ import '#tests/setup/setup-test-env.ts'
import { faker } from '@faker-js/faker'
import { expect, test } from 'bun:test'
import { createMessage, createRecipient, createUser } from '#tests/db-utils.ts'
-import { getScheduleWindow } from './cron.server.ts'
import { sendNextTexts } from './cron-runner.server.ts'
+import { getScheduleWindow } from './cron.server.ts'
import { prisma } from './db.server.ts'
test('does not send any texts if there are none to be sent', async () => {
diff --git a/app/utils/extended-theme.ts b/app/utils/extended-theme.ts
index 02317d67..a7c691bd 100644
--- a/app/utils/extended-theme.ts
+++ b/app/utils/extended-theme.ts
@@ -46,6 +46,57 @@ export const extendedTheme = {
DEFAULT: 'hsl(var(--card))',
foreground: 'hsl(var(--card-foreground))',
},
+ overlay: 'hsl(var(--overlay))',
+ inverse: 'hsl(var(--inverse))',
+ brand: {
+ DEFAULT: 'hsl(var(--brand))',
+ foreground: 'hsl(var(--brand-foreground))',
+ },
+ 'brand-soft': {
+ DEFAULT: 'hsl(var(--brand-soft))',
+ foreground: 'hsl(var(--brand-soft-foreground))',
+ },
+ warm: {
+ DEFAULT: 'hsl(var(--warm))',
+ foreground: 'hsl(var(--warm-foreground))',
+ },
+ warning: {
+ DEFAULT: 'hsl(var(--warning))',
+ foreground: 'hsl(var(--warning-foreground))',
+ },
+ 'banner-trial': {
+ DEFAULT: 'hsl(var(--banner-trial))',
+ foreground: 'hsl(var(--banner-trial-foreground))',
+ },
+ 'banner-upgrade': {
+ DEFAULT: 'hsl(var(--banner-upgrade))',
+ foreground: 'hsl(var(--banner-upgrade-foreground))',
+ },
+ 'price-basic': 'hsl(var(--price-basic))',
+ 'price-premium': 'hsl(var(--price-premium))',
+ 'hero-orb': 'hsl(var(--hero-orb))',
+ 'hero-sparkle': 'hsl(var(--hero-sparkle))',
+ 'marketing-feature': {
+ DEFAULT: 'hsl(var(--marketing-feature))',
+ foreground: 'hsl(var(--marketing-feature-foreground))',
+ muted: 'hsl(var(--marketing-feature-muted))',
+ accent: 'hsl(var(--marketing-feature-accent))',
+ 'accent-secondary': 'hsl(var(--marketing-feature-accent-secondary))',
+ },
+ 'marketing-step-index': 'hsl(var(--marketing-step-index))',
+ 'marketing-cta': {
+ DEFAULT: 'hsl(var(--marketing-cta))',
+ foreground: 'hsl(var(--marketing-cta-foreground))',
+ accent: 'hsl(var(--marketing-cta-accent))',
+ },
+ 'message-bubble': {
+ DEFAULT: 'hsl(var(--message-bubble))',
+ foreground: 'hsl(var(--message-bubble-foreground))',
+ },
+ 'message-card': {
+ DEFAULT: 'hsl(var(--message-card))',
+ foreground: 'hsl(var(--message-card-foreground))',
+ },
},
borderRadius: {
lg: 'var(--radius)',