Merge and use newsletter-api for immediate welcome emails

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2025-12-23 01:35:09 -05:00
commit 0ee8179093
5 changed files with 59 additions and 7 deletions

13
Dockerfile Normal file
View File

@ -0,0 +1,13 @@
FROM node:20-alpine AS builder
WORKDIR /app
RUN corepack enable && corepack prepare pnpm@latest --activate
COPY package.json pnpm-lock.yaml* package-lock.json* ./
RUN if [ -f pnpm-lock.yaml ]; then pnpm install --frozen-lockfile; elif [ -f package-lock.json ]; then npm ci; else npm install; fi
COPY . .
RUN if [ -f pnpm-lock.yaml ]; then pnpm build; else npm run build; fi
FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder /app/out /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View File

@ -8,6 +8,7 @@ const _geist = Geist({ subsets: ["latin"] })
const _geistMono = Geist_Mono({ subsets: ["latin"] })
export const metadata: Metadata = {
metadataBase: new URL("https://alltor.net"),
title: "alltor.net - The Alternative Internet",
description:
"A distributed, local-first, collaborative digital ecosystem. Access the alternative internet through physical USB keys and local mesh networks.",
@ -15,6 +16,30 @@ export const metadata: Metadata = {
icons: {
icon: "data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🧅</text></svg>",
},
openGraph: {
title: "alltor.net - The Alternative Internet",
description:
"A distributed, local-first, collaborative digital ecosystem. Access the alternative internet through physical USB keys and local mesh networks.",
url: "https://alltor.net",
siteName: "alltor.net",
images: [
{
url: "/og-image.jpg",
width: 1200,
height: 630,
alt: "alltor.net - The Alternative Internet",
},
],
locale: "en_US",
type: "website",
},
twitter: {
card: "summary_large_image",
title: "alltor.net - The Alternative Internet",
description:
"A distributed, local-first, collaborative digital ecosystem. Access the alternative internet through physical USB keys and local mesh networks.",
images: ["/og-image.jpg"],
},
}
export default function RootLayout({

View File

@ -3,7 +3,7 @@
import { useState } from "react"
import { Button } from "@/components/ui/button"
const LISTMONK_URL = "https://newsletter.jeffemmett.com"
const NEWSLETTER_API = "https://newsletter.jeffemmett.com/api/subscribe"
const LIST_UUID = "0c541da4-3f04-4e72-978a-5a328b43c995" // Alltornet list
export function NewsletterSignup() {
@ -19,21 +19,20 @@ export function NewsletterSignup() {
setStatus("loading")
try {
const response = await fetch(`${LISTMONK_URL}/subscription/form`, {
const response = await fetch(`${NEWSLETTER_API}/subscribe`, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Type": "application/json",
},
body: new URLSearchParams({
body: JSON.stringify({
email: email,
list: LIST_UUID,
name: "",
list_uuid: LIST_UUID,
}),
})
if (response.ok) {
setStatus("success")
setMessage("Check your email to confirm your subscription!")
setMessage("Connect to the Alltor.net. Something's emerging.")
setEmail("")
} else {
throw new Error("Subscription failed")

15
nginx.conf Normal file
View File

@ -0,0 +1,15 @@
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html index.htm;
location / {
try_files $uri $uri/ $uri.html =404;
}
error_page 404 /404.html;
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
}

BIN
public/og-image.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB