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
4 changes: 2 additions & 2 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />
import "./.next/dev/types/routes.d.ts";
import "./.next/dev/types/root-params.d.ts";
import "./.next/types/routes.d.ts";
import "./.next/types/root-params.d.ts";

// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
42 changes: 21 additions & 21 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"@marsidev/react-turnstile": "^1.6.3",
"@mdx-js/mdx": "^3.1.1",
"@mdx-js/react": "^3.1.1",
"@next/bundle-analyzer": "16.4.3",
"@next/bundle-analyzer": "16.4.4",
"@number-flow/react": "^0.6.2",
"@opentelemetry/api": "^1.10.0",
"@opentelemetry/exporter-logs-otlp-http": "^0.300.0",
Expand All @@ -49,39 +49,39 @@
"@radix-ui/react-dropdown-menu": "^2.1.25",
"@radix-ui/react-slot": "^1.4.0",
"@radix-ui/react-tooltip": "^1.3.0",
"@react-email/render": "^2.1.1",
"@react-email/render": "^2.2.0",
"@t3-oss/env-nextjs": "^0.13.11",
"@tailwindcss/typography": "^0.5.20",
"@tanstack/react-query": "^5.105.0",
"@trpc/client": "11.19.0",
"@trpc/next": "11.19.0",
"@trpc/react-query": "11.19.0",
"@trpc/server": "11.19.0",
"@tanstack/react-query": "^5.105.1",
"@trpc/client": "11.22.1",
"@trpc/next": "11.22.1",
"@trpc/react-query": "11.22.1",
"@trpc/server": "11.22.1",
"@types/mdx": "^2.0.14",
"@upstash/ratelimit": "^2.2.0",
"@upstash/redis": "^1.40.0",
"@upstash/redis": "^1.41.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"date-fns": "^4.4.0",
"fathom-client": "^3.7.2",
"feed": "^6.0.0",
"gray-matter": "^4.0.3",
"lucide-react": "^1.62.0",
"lucide-react": "^1.66.0",
"micro": "^10.0.1",
"next": "16.4.3",
"next": "16.4.4",
"next-cloudinary": "^7.0.0",
"next-mdx-remote": "6.0.0",
"nuqs": "^2.10.2",
"pluralize": "^8.0.0",
"postcss": "^8.5.32",
"posthog-js": "^1.440.0",
"posthog-node": "^5.57.2",
"posthog-js": "^1.444.2",
"posthog-node": "^5.61.2",
"prism-react-renderer": "^2.4.1",
"react": "19.3.1",
"react-aria": "^3.52.1",
"react-dom": "19.3.1",
"react-email": "6.11.4",
"react-email": "6.11.6",
"react-hook-form": "^7.91.0",
"react-stately": "^3.51.0",
"rehype-img-size": "^1.0.1",
Expand All @@ -90,8 +90,8 @@
"remark-mdx": "^3.1.1",
"remark-parse": "^11.0.0",
"remark-stringify": "^11.0.0",
"resend": "^6.35.0",
"sass": "^1.106.1",
"resend": "^6.37.0",
"sass": "^1.107.1",
"sharp": "^0.35.5",
"slugify": "^1.6.9",
"sonner": "^2.0.8",
Expand All @@ -105,32 +105,32 @@
"devDependencies": {
"@eslint/js": "^10.0.1",
"@ianvs/prettier-plugin-sort-imports": "^4.7.1",
"@next/eslint-plugin-next": "16.4.3",
"@next/eslint-plugin-next": "16.4.4",
"@playwright/test": "1.64.1",
"@tailwindcss/postcss": "^4.3.3",
"@testing-library/jest-dom": "^7.0.1",
"@testing-library/react": "^16.3.3",
"@testing-library/user-event": "^14.6.8",
"@types/eslint-plugin-jsx-a11y": "^6.10.1",
"@types/mdast": "^4.0.4",
"@types/node": "^26.6.4",
"@types/node": "^26.6.6",
"@types/pluralize": "^0.0.33",
"@types/react": "19.3.0",
"@typescript-eslint/eslint-plugin": "^8.72.1",
"@typescript-eslint/parser": "^8.72.1",
"@vitejs/plugin-react": "^6.1.2",
"@vitejs/plugin-react": "^6.2.1",
"babel-plugin-react-compiler": "^1.0.0",
"dotenv": "^18.0.9",
"eslint": "10.13.0",
"eslint": "10.14.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-unused-imports": "^4.4.1",
"github-slugger": "^2.0.0",
"jiti": "^2.7.0",
"jsdom": "^30.1.3",
"knip": "^6.43.0",
"pagefind": "^1.5.2",
"knip": "^6.44.1",
"pagefind": "^1.6.0",
"prettier": "^3.9.9",
"prettier-plugin-tailwindcss": "^0.8.1",
"schema-dts": "^2.1.0",
Expand Down
775 changes: 404 additions & 371 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pnpm-workspace.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
overrides:
next: 16.4.3
next: 16.4.4
tailwindcss: ^4.3.1
minimatch@3>brace-expansion: 1.1.21
gray-matter>js-yaml: 3.15.2
Expand Down
7 changes: 5 additions & 2 deletions scripts/sync-newsletter-to-resend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,14 @@ async function main() {
);
}

const subject = frontmatter.subject ?? frontmatter.title;

// Render to HTML
const html = await render(
React.createElement(NewsletterEmail, {
title: subject,
content: cleanContent,
excerpt: frontmatter.excerpt,
excerpt: frontmatter.previewText ?? frontmatter.excerpt,
coverImage: frontmatter.coverImagePublicId
? getCloudinaryImageUrl(frontmatter.coverImagePublicId)
: undefined,
Expand All @@ -331,7 +334,7 @@ async function main() {
// Upsert broadcast
const result = await upsertBroadcast({
slug,
subject: frontmatter.title,
subject,
html,
from: FROM_ADDRESS,
disableClickTracking: hasSponsor,
Expand Down
4 changes: 4 additions & 0 deletions src/data/content-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ export const toRendered = <T extends MarkdownDocument>({
export type NewsletterMetadata = BaseFrontmatter & {
coverImagePublicId: string;
excerpt: string;
// Email subject line. `title` stays the search/page title; falls back to it when absent.
subject?: string;
// Email client preview text. Falls back to `excerpt` when absent.
previewText?: string;
};

/**
Expand Down
2 changes: 1 addition & 1 deletion src/utils/email/templates/EmailLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export const EmailLayout = ({
<Text style={{ marginBottom: '10px' }} className="my-0 text-sm">
© {new Date().getFullYear()} &bull; 💌 Tiny Improvements &bull;{' '}
<Link
href="https://mikebifulco.com/newsletter"
href="https://mikebifulco.com"
className="text-pink-600"
>
mikebifulco.com
Expand Down
15 changes: 10 additions & 5 deletions src/utils/email/templates/NewsletterEmail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Column, Img, Link, Markdown, Row, Text } from 'react-email';
import { EmailLayout } from './EmailLayout';

type NewsletterEmailProps = {
title: string;
content: string;
excerpt: string;
coverImage?: string;
Expand All @@ -17,6 +18,7 @@ type NewsletterEmailProps = {
* The content can include inline HTML for custom components like SponsoredSection.
*/
export const NewsletterEmail = ({
title = 'Sample newsletter title',
content = 'lorem ipsum dolor sit amet this is just sample content for email preview',
excerpt = 'Preview text for email clients',
coverImage = 'https://picsum.photos/1200/630',
Expand All @@ -32,7 +34,7 @@ export const NewsletterEmail = ({
<Column>
<Img
src={coverImage}
alt="Newsletter cover image"
alt={title}
className="mt-2 w-full rounded"
style={{
maxWidth: '100%',
Expand Down Expand Up @@ -63,13 +65,16 @@ export const NewsletterEmail = ({
<Row>
<Column>
<Text className="italic text-gray-500">
Thanks for reading 💌 Tiny Improvements. If you found this helpful,
I&apos;d love it if you{' '}
Thanks for reading 💌 Tiny Improvements. Got a thought, a question,
or a story of your own? Hit reply. It comes straight to me.
</Text>
<Text className="italic text-gray-500">
If this was useful, forward it to a friend, or send them to{' '}
<Link
href="https://mikebifulco.com/newsletter"
href="https://mikebifulco.com/subscribe"
className="text-pink-600"
>
share it with a friend
mikebifulco.com/subscribe
</Link>
. It helps me out a great deal!
</Text>
Expand Down
Loading