feat: redesign page heroes, implement organic markers, and streamline contact flow
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 1m24s
Build & Deploy / 🏗️ Build (push) Failing after 4m3s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 5s
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 6s
Build & Deploy / 🧪 QA (push) Failing after 1m24s
Build & Deploy / 🏗️ Build (push) Failing after 4m3s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🩺 Health Check (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 5s
- Refined hero sections for About, Blog, Websites, and Case Studies for a bespoke industrial entry point. - Redesigned Marker component using layered SVG paths for an organic, hand-drawn highlighter effect. - Restored technical precision in ArchitectureVisualizer with refined line thickness. - Streamlined contact page by removing generic headers and prioritizing the configurator/gateway. - Updated technical references to reflect self-hosted Gitea infrastructure. - Cleaned up unused imports and addressed linting warnings across modified pages.
This commit is contained in:
20
apps/web/src/lib/env.ts
Normal file
20
apps/web/src/lib/env.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { z } from "zod";
|
||||
import { validateMintelEnv } from "@mintel/next-utils";
|
||||
|
||||
/**
|
||||
* Environment variable schema extension.
|
||||
*/
|
||||
const envExtension = {
|
||||
// Mail Configuration
|
||||
MAIL_HOST: z.string().optional(),
|
||||
MAIL_PORT: z.coerce.number().optional().default(587),
|
||||
MAIL_USER: z.string().optional(),
|
||||
MAIL_PASS: z.string().optional(),
|
||||
MAIL_FROM: z.string().optional().default("marc@mintel.me"),
|
||||
MAIL_RECIPIENTS: z.string().optional().default("marc@mintel.me"),
|
||||
};
|
||||
|
||||
/**
|
||||
* Validated environment object.
|
||||
*/
|
||||
export const env = validateMintelEnv(envExtension);
|
||||
85
apps/web/src/lib/mail/mailer.ts
Normal file
85
apps/web/src/lib/mail/mailer.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
import nodemailer from "nodemailer";
|
||||
import { env } from "../env";
|
||||
|
||||
let transporterInstance: nodemailer.Transporter | null = null;
|
||||
|
||||
function getTransporter() {
|
||||
if (transporterInstance) return transporterInstance;
|
||||
|
||||
if (!env.MAIL_HOST) {
|
||||
// In development, we might not have mail configured, so we log instead of throwing
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.warn(
|
||||
"MAIL_HOST is not configured. Emails will be logged to console.",
|
||||
);
|
||||
return null;
|
||||
}
|
||||
throw new Error(
|
||||
"MAIL_HOST is not configured. Please check your environment variables.",
|
||||
);
|
||||
}
|
||||
|
||||
transporterInstance = nodemailer.createTransport({
|
||||
host: env.MAIL_HOST,
|
||||
port: env.MAIL_PORT,
|
||||
secure: env.MAIL_PORT === 465,
|
||||
auth: {
|
||||
user: env.MAIL_USER,
|
||||
pass: env.MAIL_PASS,
|
||||
},
|
||||
});
|
||||
|
||||
return transporterInstance;
|
||||
}
|
||||
|
||||
interface SendEmailOptions {
|
||||
to?: string | string[];
|
||||
replyTo?: string;
|
||||
subject: string;
|
||||
html: string;
|
||||
}
|
||||
|
||||
export async function sendEmail({
|
||||
to,
|
||||
replyTo,
|
||||
subject,
|
||||
html,
|
||||
}: SendEmailOptions) {
|
||||
const recipients = to || env.MAIL_RECIPIENTS;
|
||||
const transporter = getTransporter();
|
||||
|
||||
const mailOptions = {
|
||||
from: env.MAIL_FROM,
|
||||
to: recipients,
|
||||
replyTo,
|
||||
subject,
|
||||
html,
|
||||
};
|
||||
|
||||
if (!transporter) {
|
||||
console.log("--- EMAIL SIMULATION ---");
|
||||
console.log("To:", recipients);
|
||||
console.log("Subject:", subject);
|
||||
console.log("HTML Output suppressed");
|
||||
console.log("--- END SIMULATION ---");
|
||||
return { success: true, messageId: "simulated-id" };
|
||||
}
|
||||
|
||||
try {
|
||||
const info = await transporter.sendMail(mailOptions);
|
||||
console.log("Email sent successfully", {
|
||||
messageId: info.messageId,
|
||||
subject,
|
||||
recipients,
|
||||
});
|
||||
return { success: true, messageId: info.messageId };
|
||||
} catch (error) {
|
||||
const errorMsg = error instanceof Error ? error.message : String(error);
|
||||
console.error("Error sending email", {
|
||||
error: errorMsg,
|
||||
subject,
|
||||
recipients,
|
||||
});
|
||||
return { success: false, error: errorMsg };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user