Initial commit: img-infinite-canvas AI design workbench MVP
Moteva-style AI design workbench replica. Home prompt creates a project; the project page provides an infinite canvas with node drag, zoom/pan, a design chat panel, history replay, image asset upload, and project save/regenerate. - Backend: go-zero, DDD layering, sqlc/pgx, optional PostgreSQL; memory or Redis cache; asynq job queue; MinIO/S3/R2/OSS object storage; sky-valley/pi agent runtime adapter. - Frontend: Next.js App Router + Vite artifact build, TypeScript, i18n, shadcn/ui components, auth (OTP/Turnstile/Google/WeChat). - Deploy: Docker Compose and k3s manifests. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
loginEmailFromName = "hello"
|
||||
loginEmailFromEmail = "hello@auth.moteva.local"
|
||||
loginEmailBrandName = "Moteva"
|
||||
)
|
||||
|
||||
type EmailTemplateOptions struct {
|
||||
FromName string
|
||||
FromEmail string
|
||||
BrandName string
|
||||
}
|
||||
|
||||
func buildLoginEmail(toEmail string, code string, opts EmailTemplateOptions) *EmailMessage {
|
||||
toEmail = normalizeEmail(toEmail)
|
||||
code = strings.TrimSpace(code)
|
||||
fromName := fallbackString(opts.FromName, loginEmailFromName)
|
||||
fromEmail := fallbackString(opts.FromEmail, loginEmailFromEmail)
|
||||
brandName := fallbackString(opts.BrandName, loginEmailBrandName)
|
||||
return &EmailMessage{
|
||||
FromName: fromName,
|
||||
FromEmail: fromEmail,
|
||||
ToEmail: toEmail,
|
||||
Subject: "Welcome to " + brandName + "!",
|
||||
Code: code,
|
||||
Text: fmt.Sprintf(
|
||||
"Hi,\n\nWelcome to us! Enter this code within the next 10 minutes to log in:\n\n%s\n\nPlease ignore this email if this wasn't you trying to create a %s account.\n\nThe %s Team",
|
||||
code,
|
||||
brandName,
|
||||
brandName,
|
||||
),
|
||||
HTML: loginEmailHTML(code, brandName),
|
||||
}
|
||||
}
|
||||
|
||||
func loginEmailHTML(code string, brandName string) string {
|
||||
escapedCode := html.EscapeString(code)
|
||||
escapedBrand := html.EscapeString(brandName)
|
||||
return `<!doctype html>
|
||||
<html>
|
||||
<body style="margin:0;padding:28px;background:#fff;font-family:Arial,Helvetica,sans-serif;color:#141922;">
|
||||
<main style="max-width:1160px;background:#f8f8f8;border-radius:36px;overflow:hidden;">
|
||||
<section style="padding:64px 40px 84px;">
|
||||
<div style="font-size:48px;font-weight:800;letter-spacing:-1px;margin-bottom:72px;">
|
||||
<span style="display:inline-grid;place-items:center;width:64px;height:64px;border-radius:50%;background:#050505;color:#fff;font-size:28px;margin-right:16px;vertical-align:middle;">M</span>
|
||||
<span style="vertical-align:middle;">` + escapedBrand + `</span>
|
||||
</div>
|
||||
<p style="font-size:30px;font-weight:800;margin:0 0 30px;">Hi,</p>
|
||||
<p style="font-size:30px;line-height:1.4;margin:0 0 110px;">Welcome to us! Enter this code within the next 10 minutes to log in:</p>
|
||||
<div style="text-align:center;font-size:96px;line-height:1;font-weight:900;text-decoration:underline;letter-spacing:2px;margin-bottom:110px;">` + escapedCode + `</div>
|
||||
<p style="font-size:29px;line-height:1.4;margin:0 0 32px;">Please ignore this email if this wasn't you trying to create a ` + escapedBrand + ` account.</p>
|
||||
<p style="font-size:30px;font-weight:900;margin:0;">The ` + escapedBrand + ` Team</p>
|
||||
</section>
|
||||
<footer style="background:#000;color:#fff;padding:44px 40px;">
|
||||
<div style="color:#50e6ff;font-size:25px;font-weight:900;letter-spacing:.4px;margin-bottom:28px;">THE DESIGN AGENT WHO CREATES BY YOUR SIDE.</div>
|
||||
<div style="font-size:22px;font-weight:800;line-height:1.35;">DIVE INTO THE AUTO-DESIGN AGENT<br/>CRAFTED FOR LIMITLESS CREATIVITY.</div>
|
||||
</footer>
|
||||
</main>
|
||||
</body>
|
||||
</html>`
|
||||
}
|
||||
|
||||
func fallbackString(value string, fallback string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return fallback
|
||||
}
|
||||
return value
|
||||
}
|
||||
Reference in New Issue
Block a user