(chore): initial MVP release

This commit is contained in:
2025-11-16 19:05:01 +05:30
commit 842fa3bce3
186 changed files with 24820 additions and 0 deletions

BIN
htdocs/app/.DS_Store vendored Normal file

Binary file not shown.

108
htdocs/app/mail/mailer.php Normal file
View File

@@ -0,0 +1,108 @@
<?php
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require_once __DIR__ . '/../../config/env.php';
require_once __DIR__ . '/templates/loader.php';
/**
* Build and optionally send mail from a file-based template.
*/
function sendMailFromTemplate(string $templateKey, bool $previewOnly = false): bool
{
$mail = new PHPMailer(true);
$email = $_ENV['MAIL_TO'];
$username = $_ENV['USERNAME'];
try {
$mail->isSMTP();
$mail->Host = $_ENV['MAIL_HOST'];
$mail->SMTPAuth = true;
$mail->Username = $_ENV['MAIL_USERNAME'];
$mail->Password = $_ENV['MAIL_PASSWORD'];
$mail->SMTPSecure = $_ENV['MAIL_ENCRYPTION'];
$mail->Port = (int) $_ENV['MAIL_PORT'];
$mail->setFrom($_ENV['MAIL_FROM'], $_ENV['MAIL_FROM_NAME']);
$mail->addAddress($email, $username);
$domain = $_ENV['DOMAIN'] ?? 'UNKNOWN DOMAIN';
$company = $_ENV['COMPANY_NAME'] ?? 'UNKNOWN COMPANY';
$github = $_ENV['GITHUB'] ?? 'UNKNOWN GITHUB';
$website = $_ENV['WEBSITE'] ?? 'UNKNOWN WEBSITE';
$projectStartYear = $_ENV['PROJECT_START_YEAR'] ?? 2025;
$currentYear = (int) date('Y');
$startYear = min((int) $projectStartYear, $currentYear);
$yearText = ($currentYear > $startYear)
? $startYear . '-' . substr((string) $currentYear, -2)
: $startYear;
// context passed to template files
$ctx = [
'email' => $email,
'username' => $username,
'domain' => $domain,
'company' => $company,
'github' => $github,
'website' => $website,
'yearText' => $yearText,
];
// 🔥 load subject + body from the selected template file
$tpl = loadMailTemplate($templateKey, $ctx);
$mail->CharSet = 'UTF-8';
$mail->Encoding = 'base64';
$mail->isHTML(true);
$mail->Subject = $tpl['subject'];
$mail->Body = $tpl['body'];
// expose everything for preview
$GLOBALS['MAIL_PREVIEW_SUBJECT'] = $mail->Subject;
$GLOBALS['MAIL_PREVIEW_BODY'] = $mail->Body;
$GLOBALS['MAIL_PREVIEW_TO'] = $email;
$GLOBALS['MAIL_PREVIEW_USERNAME'] = $username;
$GLOBALS['MAIL_PREVIEW_DOMAIN'] = $domain;
$GLOBALS['MAIL_PREVIEW_COMPANY'] = $company;
$GLOBALS['MAIL_PREVIEW_FROM'] = $_ENV['MAIL_FROM'];
$GLOBALS['MAIL_PREVIEW_FROM_NAME'] = $_ENV['MAIL_FROM_NAME'];
$GLOBALS['MAIL_PREVIEW_MAIL_HOST'] = $_ENV['MAIL_HOST'] ?? null;
$GLOBALS['MAIL_PREVIEW_MAIL_USERNAME'] = $_ENV['MAIL_USERNAME'] ?? null;
$GLOBALS['MAIL_PREVIEW_MAIL_PORT'] = $_ENV['MAIL_PORT'] ?? null;
$GLOBALS['MAIL_PREVIEW_MAIL_ENCRYPTION'] = $_ENV['MAIL_ENCRYPTION'] ?? null;
$GLOBALS['MAIL_PREVIEW_PROJECT_START'] = $startYear;
$GLOBALS['MAIL_PREVIEW_CURRENT_YEAR'] = $currentYear;
$GLOBALS['MAIL_PREVIEW_MAIL_PASSWORD'] = empty($_ENV['MAIL_PASSWORD']) ? 'not set' : '•••• (configured)';
// template info for UI
$GLOBALS['MAIL_PREVIEW_TEMPLATE_KEY'] = $tpl['key'];
$GLOBALS['MAIL_PREVIEW_TEMPLATE_LABEL'] = $tpl['label'];
$GLOBALS['MAIL_PREVIEW_TEMPLATES_INDEX'] = getMailTemplatesIndex($ctx);
if ($previewOnly) {
return true;
}
$mail->send();
return true;
} catch (Exception $e) {
error_log('Mailer Error: ' . $mail->ErrorInfo);
return false;
} catch (\Throwable $e) {
error_log('Mailer Exception: ' . $e->getMessage());
return false;
}
}
/**
* Backwards-compatible wrapper.
* Default template: 'quary'
*/
function sendAccountCreationMail(bool $previewOnly = false, string $templateKey = 'quary'): bool
{
return sendMailFromTemplate($templateKey, $previewOnly);
}

View File

@@ -0,0 +1,108 @@
<?php
$email = $ctx['email'] ?? '';
$username = $ctx['username'] ?? '';
$domain = $ctx['domain'] ?? '';
$company = $ctx['company'] ?? '';
$github = $ctx['github'] ?? '';
$website = $ctx['website'] ?? '';
$yearText = $ctx['yearText'] ?? '';
$subject = "{$domain} - Query Response #10";
$body = <<<HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@300;400;600;700&display=swap" rel="stylesheet" />
<style type="text/css">
@import url('https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@300;400;600;700&display=swap');
.body-font { font-family: 'Lexend Deca', -apple-system !important; }
.heading-font { font-family: 'Lexend Deca', -apple-system !important; font-weight: 600; }
a { color: #1d4ed8; }
</style>
</head>
<body class="body-font" style="margin:0;padding:0;background-color:#ffffff;color:#0f172a;font-family:'Lexend Deca', -apple-system;">
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background:#ffffff;padding:24px 12px;font-family:'Lexend Deca', -apple-system;">
<tr>
<td align="center">
<table role="presentation" cellpadding="0" cellspacing="0" width="640" style="max-width:640px;width:100%;border-collapse:collapse;text-align:left;font-family:'Lexend Deca', -apple-system;">
<tr>
<td style="padding-top:28px;padding-bottom:8px;text-align:center;">
<h1 class="heading-font" style="font-size:28px;line-height:34px;margin:0;font-weight:600;color:#0f172a;text-align:center;font-family:'Lexend Deca', -apple-system;">
Query Response #10
</h1>
</td>
</tr>
<tr>
<td style="padding:18px 16px 8px 16px;background:#ffffff;font-family:'Lexend Deca', -apple-system;">
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
Hi <strong style="color:#0f172a;">{$username}</strong>,
</p>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
<strong style="color:#0f172a;">{$domain}</strong> had received a query about (the things..).
We're pleased to announce you that your <strong style="color:#0f172a;">{$domain}</strong>
query has been approved. Do you have any other questions or suggestions? We're always here to help.
</p>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
We reviewed your recommendations and we want to thank you for your input.
We're a small, quiet corner of the internet, did you want to join us to grow it further?
Send your github username via reply to this email and we will get back to you;
After accepting the invitation, you can start contributing to the project.
</p>
<div style="height:1px;background:#e6e9ef;margin:20px 0;"></div>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
This query was received by the email address:
<a href="mailto:{$email}" style="color:#0f172a;font-family:'Lexend Deca', -apple-system;">{$email}</a>.
</p>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system, BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;">
🪢 <strong style="color:#0f172a;">GitHub:</strong> {$github}<br>
</p>
<div style="height:1px;background:#e6e9ef;margin:20px 0;"></div>
<p style="font-size:14px;line-height:20px;color:#6b7280;margin:0 0 12px 0;font-family:'Lexend Deca', -apple-system;">
If you did not make this query, or believe we contacted the wrong person, kidnly ignore this email.
However, if you have any new queries, requests, or wish to contribute, feel free to reach out to us at this email address.
</p>
<p style="font-size:16px;line-height:18px;color:#475569;margin:18px 0 0 0;font-family:'Lexend Deca', -apple-system;">
Sincerely,
</p>
<p style="font-size:16px;line-height:18px;color:#0f172a;font-weight:600;margin:6px 0 0 0;font-family:'Lexend Deca', -apple-system;">
{$domain} Support
</p>
</td>
</tr>
<tr>
<td style="padding:14px 12px 28px 12px;font-family:'Lexend Deca', -apple-system;">
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background:#f8fafc;padding:12px;border-radius:6px;font-family:'Lexend Deca', -apple-system;">
<tr>
<td style="text-align:center;font-size:12px;color:#6b7280;line-height:20px;font-family:'Lexend Deca', -apple-system;">
<div style="margin-bottom:4px;font-family:'Lexend Deca', -apple-system;">
<a href="https://{$domain}.in" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">{$domain}</a> |
<a href="https://{$domain}.in/support" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">Support</a> |
<a href="https://{$domain}.in/privacy-policy" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">Privacy Policy</a>
</div>
<div style="font-size:12px;color:#475569;font-family:'Lexend Deca', -apple-system;">
A small community under {$company}.<br>
&copy; {$yearText} {$company}. All rights reserved.
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
HTML;
return [
'label' => "{$domain} Approved Temp.",
'subject' => $subject,
'body' => $body,
];

View File

@@ -0,0 +1,102 @@
<?php
$email = $ctx['email'] ?? '';
$username = $ctx['username'] ?? '';
$domain = $ctx['domain'] ?? '';
$company = $ctx['company'] ?? '';
$github = $ctx['github'] ?? '';
$website = $ctx['website'] ?? '';
$yearText = $ctx['yearText'] ?? '';
$subject = "{$domain} - Query Response #11";
$body = <<<HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@300;400;600;700&display=swap" rel="stylesheet" />
<style type="text/css">
@import url('https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@300;400;600;700&display=swap');
.body-font { font-family: 'Lexend Deca', -apple-system !important; }
.heading-font { font-family: 'Lexend Deca', -apple-system !important; font-weight: 600; }
a { color: #1d4ed8; }
</style>
</head>
<body class="body-font" style="margin:0;padding:0;background-color:#ffffff;color:#0f172a;font-family:'Lexend Deca', -apple-system;">
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background:#ffffff;padding:24px 12px;font-family:'Lexend Deca', -apple-system;">
<tr>
<td align="center">
<table role="presentation" cellpadding="0" cellspacing="0" width="640" style="max-width:640px;width:100%;border-collapse:collapse;text-align:left;font-family:'Lexend Deca', -apple-system;">
<tr>
<td style="padding-top:28px;padding-bottom:8px;text-align:center;">
<h1 class="heading-font" style="font-size:28px;line-height:34px;margin:0;font-weight:600;color:#0f172a;text-align:center;font-family:'Lexend Deca', -apple-system;">
Query Response #11
</h1>
</td>
</tr>
<tr>
<td style="padding:18px 16px 8px 16px;background:#ffffff;font-family:'Lexend Deca', -apple-system;">
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
Hi <strong style="color:#0f172a;">{$username}</strong>,
</p>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
<strong style="color:#0f172a;">{$domain}</strong> had received a query about (the things..).
We're so sorry to announce you that your <strong style="color:#0f172a;">{$domain}</strong>
query has been declined. Do you have any other questions or suggestions? We're always here to help.
</p>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
We reviewed your recommendations and we appreciate your valuable input;
but unfortunately, we are unable to implement your suggestions at this time.
</p>
<div style="height:1px;background:#e6e9ef;margin:20px 0;"></div>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
This query was received by the email address:
<a href="mailto:{$email}" style="color:#0f172a;font-family:'Lexend Deca', -apple-system;">{$email}</a>.
</p>
<div style="height:1px;background:#e6e9ef;margin:20px 0;"></div>
<p style="font-size:14px;line-height:20px;color:#6b7280;margin:0 0 12px 0;font-family:'Lexend Deca', -apple-system;">
If you did not make this query, or believe we contacted the wrong person, kidnly ignore this email.
However, if you have any new queries, requests, or wish to contribute, feel free to reach out to us at this email address.
</p>
<p style="font-size:16px;line-height:18px;color:#475569;margin:18px 0 0 0;font-family:'Lexend Deca', -apple-system;">
Sincerely,
</p>
<p style="font-size:16px;line-height:18px;color:#0f172a;font-weight:600;margin:6px 0 0 0;font-family:'Lexend Deca', -apple-system;">
{$domain} Support
</p>
</td>
</tr>
<tr>
<td style="padding:14px 12px 28px 12px;font-family:'Lexend Deca', -apple-system;">
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background:#f8fafc;padding:12px;border-radius:6px;font-family:'Lexend Deca', -apple-system;">
<tr>
<td style="text-align:center;font-size:12px;color:#6b7280;line-height:20px;font-family:'Lexend Deca', -apple-system;">
<div style="margin-bottom:4px;font-family:'Lexend Deca', -apple-system;">
<a href="https://{$domain}.in" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">{$domain}</a> |
<a href="https://{$domain}.in/support" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">Support</a> |
<a href="https://{$domain}.in/privacy-policy" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">Privacy Policy</a>
</div>
<div style="font-size:12px;color:#475569;font-family:'Lexend Deca', -apple-system;">
A small community under {$company}.<br>
&copy; {$yearText} {$company}. All rights reserved.
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
HTML;
return [
'label' => "{$domain} Declined Temp.",
'subject' => $subject,
'body' => $body,
];

View File

@@ -0,0 +1,89 @@
<?php
// app/mail/templates/loader.php
/**
* Static map: do NOT use $domain here (no ctx available yet)
*/
function mailTemplateMap(): array
{
return [
'quary' => [
'file' => __DIR__ . '/query-template.php',
],
'thanks' => [
'file' => __DIR__ . '/thanks-template.php',
],
'approve' => [
'file' => __DIR__ . '/approved-template.php',
],
'decline' => [
'file' => __DIR__ . '/declined-template.php',
],
];
}
/**
* Load a single template by key.
*/
function loadMailTemplate(string $key, array $ctx): array
{
$map = mailTemplateMap();
if (!isset($map[$key])) {
throw new RuntimeException("Unknown mail template key: {$key}");
}
$file = $map[$key]['file'];
$label = $map[$key]['label'];
// Make $ctx visible inside template file
$template = require $file;
if (!is_array($template)) {
throw new RuntimeException("Template file {$file} did not return array");
}
// attach meta
$template['key'] = $key;
$template['label'] = $template['label'] ?? $label;
return $template;
}
/**
* Build index for dropdown (dynamic domain support)
*/
function getMailTemplatesIndex(array $ctx): array
{
$map = mailTemplateMap();
$index = [];
$domain = $ctx['domain'] ?? '';
foreach ($map as $key => $meta) {
$label = $meta['label'];
if ($domain) {
if ($key === 'quary') {
$label = "{$domain} Query Response";
}
if ($key === 'thanks') {
$label = "{$domain} Thanks Reaching";
}
if ($key === 'approve') {
$label = "{$domain} Approved Temp.";
}
if ($key === 'decline') {
$label = "{$domain} Declined Temp.";
}
}
$index[] = [
'key' => $key,
'label' => $label,
];
}
return $index;
}

View File

@@ -0,0 +1,107 @@
<?php
$email = $ctx['email'] ?? '';
$username = $ctx['username'] ?? '';
$domain = $ctx['domain'] ?? '';
$company = $ctx['company'] ?? '';
$github = $ctx['github'] ?? '';
$website = $ctx['website'] ?? '';
$yearText = $ctx['yearText'] ?? '';
$subject = "{$domain} - Query Response #09";
$body = <<<HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@300;400;600;700&display=swap" rel="stylesheet" />
<style type="text/css">
@import url('https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@300;400;600;700&display=swap');
.body-font { font-family: 'Lexend Deca', -apple-system !important; }
.heading-font { font-family: 'Lexend Deca', -apple-system !important; font-weight: 600; }
a { color: #1d4ed8; }
</style>
</head>
<body class="body-font" style="margin:0;padding:0;background-color:#ffffff;color:#0f172a;font-family:'Lexend Deca', -apple-system;">
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background:#ffffff;padding:24px 12px;font-family:'Lexend Deca', -apple-system;">
<tr>
<td align="center">
<table role="presentation" cellpadding="0" cellspacing="0" width="640" style="max-width:640px;width:100%;border-collapse:collapse;text-align:left;font-family:'Lexend Deca', -apple-system;">
<tr>
<td style="padding-top:28px;padding-bottom:8px;text-align:center;">
<h1 class="heading-font" style="font-size:28px;line-height:34px;margin:0;font-weight:600;color:#0f172a;text-align:center;font-family:'Lexend Deca', -apple-system;">
Query Response #09
</h1>
</td>
</tr>
<tr>
<td style="padding:18px 16px 8px 16px;background:#ffffff;font-family:'Lexend Deca', -apple-system;">
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
Hi <strong style="color:#0f172a;">{$username}</strong>,
</p>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
<strong style="color:#0f172a;">{$domain}</strong> had received a query about createing the authentication system on the platfrom.
We're pleased to announce you that <strong style="color:#0f172a;">{$domain}</strong>
AUTH system has been successfully created. i18n isnt available yet for everywhere -so if you're comfortable with English, everything should work fine for now.
</p>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
Weve added a few resources, such as our website and GitHub, to help you explore the AUTH system.
We're a small, quiet corner of the internet built by a few of us who still believe the
web can be yours again.
</p>
<div style="height:1px;background:#e6e9ef;margin:20px 0;"></div>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
This query was received for the email address:
<a href="mailto:{$email}" style="color:#0f172a;font-family:'Lexend Deca', -apple-system;">{$email}</a>.
</p>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system, BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,sans-serif;">
🪢 <strong style="color:#0f172a;">GitHub:</strong> {$github}<br>
♻️ <strong style="color:#0f172a;">Website:</strong> {$website}
</p>
<div style="height:1px;background:#e6e9ef;margin:20px 0;"></div>
<p style="font-size:14px;line-height:20px;color:#6b7280;margin:0 0 12px 0;font-family:'Lexend Deca', -apple-system;">
If you did not make this query, or believe we contacted the wrong person, kindly ignore this email.
However, if you have any new queries, requests, or wish to contribute, feel free to reach out to us at this email address.
</p>
<p style="font-size:16px;line-height:18px;color:#475569;margin:18px 0 0 0;font-family:'Lexend Deca', -apple-system;">
Sincerely,
</p>
<p style="font-size:16px;line-height:18px;color:#0f172a;font-weight:600;margin:6px 0 0 0;font-family:'Lexend Deca', -apple-system;">
{$domain} Support
</p>
</td>
</tr>
<tr>
<td style="padding:14px 12px 28px 12px;font-family:'Lexend Deca', -apple-system;">
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background:#f8fafc;padding:12px;border-radius:6px;font-family:'Lexend Deca', -apple-system;">
<tr>
<td style="text-align:center;font-size:12px;color:#6b7280;line-height:20px;font-family:'Lexend Deca', -apple-system;">
<div style="margin-bottom:4px;font-family:'Lexend Deca', -apple-system;">
<a href="https://{$domain}.in" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">{$domain}</a> |
<a href="https://{$domain}.in/support" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">Support</a> |
<a href="https://{$domain}.in/privacy-policy" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">Privacy Policy</a>
</div>
<div style="font-size:12px;color:#475569;font-family:'Lexend Deca', -apple-system;">
A small community under {$company}.<br>
&copy; {$yearText} {$company}. All rights reserved.
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
HTML;
return [
'label' => "{$domain} Query Response",
'subject' => $subject,
'body' => $body,
];

View File

@@ -0,0 +1,103 @@
<?php
$email = $ctx['email'] ?? '';
$username = $ctx['username'] ?? '';
$domain = $ctx['domain'] ?? '';
$company = $ctx['company'] ?? '';
$github = $ctx['github'] ?? '';
$website = $ctx['website'] ?? '';
$yearText = $ctx['yearText'] ?? '';
$subject = "{$domain} - Thanks For Reaching Out";
$body = <<<HTML
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@300;400;600;700&display=swap" rel="stylesheet" />
<style type="text/css">
@import url('https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@300;400;600;700&display=swap');
.body-font { font-family: 'Lexend Deca', -apple-system !important; }
.heading-font { font-family: 'Lexend Deca', -apple-system !important; font-weight: 600; }
a { color: #1d4ed8; }
</style>
</head>
<body class="body-font" style="margin:0;padding:0;background-color:#ffffff;color:#0f172a;font-family:'Lexend Deca', -apple-system;">
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background:#ffffff;padding:24px 12px;font-family:'Lexend Deca', -apple-system;">
<tr>
<td align="center">
<table role="presentation" cellpadding="0" cellspacing="0" width="640" style="max-width:640px;width:100%;border-collapse:collapse;text-align:left;font-family:'Lexend Deca', -apple-system;">
<tr>
<td style="padding-top:28px;padding-bottom:8px;text-align:center;">
<h1 class="heading-font" style="font-size:28px;line-height:34px;margin:0;font-weight:600;color:#0f172a;text-align:center;font-family:'Lexend Deca', -apple-system;">
Thanks For Reaching Out
</h1>
</td>
</tr>
<tr>
<td style="padding:18px 16px 8px 16px;background:#ffffff;font-family:'Lexend Deca', -apple-system;">
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
Hi <strong style="color:#0f172a;">{$username}</strong>,
</p>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
<strong style="color:#0f172a;">{$domain}</strong> has received the query and our team has started reviewing the details youve shared.
We're pleased to thank you for spending your precious time with <strong style="color:#0f172a;">{$domain}</strong>
. i18n support isnt available in all regions yet, so were sorry if you experienced any issues.
</p>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
Well review your recommendation and let you know whether we can use it or not.
We're a small, quiet corner of the internet built by a few of us who still believe the
web can be yours again.
</p>
<div style="height:1px;background:#e6e9ef;margin:20px 0;"></div>
<p style="font-size:16px;line-height:22px;color:#475569;margin:0 0 16px 0;font-family:'Lexend Deca', -apple-system;">
This query was received by the email address:
<a href="mailto:{$email}" style="color:#0f172a;font-family:'Lexend Deca', -apple-system;">{$email}</a>.
</p>
<div style="height:1px;background:#e6e9ef;margin:20px 0;"></div>
<p style="font-size:14px;line-height:20px;color:#6b7280;margin:0 0 12px 0;font-family:'Lexend Deca', -apple-system;">
If you did not make this query, or believe we contacted the wrong person, kidnly ignore this email.
However, if you have any new quaries, requests, or wish to contribute, feel free to reach out to us at this email address.
</p>
<p style="font-size:16px;line-height:18px;color:#475569;margin:18px 0 0 0;font-family:'Lexend Deca', -apple-system;">
Sincerely,
</p>
<p style="font-size:16px;line-height:18px;color:#0f172a;font-weight:600;margin:6px 0 0 0;font-family:'Lexend Deca', -apple-system;">
{$domain} Support
</p>
</td>
</tr>
<tr>
<td style="padding:14px 12px 28px 12px;font-family:'Lexend Deca', -apple-system;">
<table role="presentation" cellpadding="0" cellspacing="0" width="100%" style="background:#f8fafc;padding:12px;border-radius:6px;font-family:'Lexend Deca', -apple-system;">
<tr>
<td style="text-align:center;font-size:12px;color:#6b7280;line-height:20px;font-family:'Lexend Deca', -apple-system;">
<div style="margin-bottom:4px;font-family:'Lexend Deca', -apple-system;">
<a href="https://{$domain}.in" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">{$domain}</a> |
<a href="https://{$domain}.in/support" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">Support</a> |
<a href="https://{$domain}.in/privacy-policy" style="color:inherit;text-decoration:none;font-family:'Lexend Deca', -apple-system;">Privacy Policy</a>
</div>
<div style="font-size:12px;color:#475569;font-family:'Lexend Deca', -apple-system;">
A small community under {$company}.<br>
&copy; {$yearText} {$company}. All rights reserved.
</div>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
HTML;
return [
'label' => "{$domain} Thanks Reaching",
'subject' => $subject,
'body' => $body,
];

View File

@@ -0,0 +1,538 @@
<?php
require_once __DIR__ . '/../mail/mailer.php';
require_once __DIR__ . '/../mail/templates/loader.php';
$selectedTemplate = $_POST['tpl'] ?? $_GET['tpl'] ?? 'quary';
$validTemplates = array_keys(mailTemplateMap());
if (!in_array($selectedTemplate, $validTemplates, true)) {
$selectedTemplate = 'quary';
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$sent = sendAccountCreationMail(false, $selectedTemplate);
$code = $sent ? 'ok' : 'fail';
header('Location: ' . $_SERVER['PHP_SELF'] . '?status=' . $code . '&tpl=' . urlencode($selectedTemplate));
exit;
}
sendAccountCreationMail(true, $selectedTemplate);
$subject = $GLOBALS['MAIL_PREVIEW_SUBJECT'] ?? '(no subject)';
$body = $GLOBALS['MAIL_PREVIEW_BODY'] ?? '';
$to = $GLOBALS['MAIL_PREVIEW_TO'] ?? '';
$username = $GLOBALS['MAIL_PREVIEW_USERNAME'] ?? '';
$domain = $GLOBALS['MAIL_PREVIEW_DOMAIN'] ?? '';
$company = $GLOBALS['MAIL_PREVIEW_COMPANY'] ?? '';
$github = $GLOBALS['MAIL_PREVIEW_GITHUB'] ?? '';
$website = $GLOBALS['MAIL_PREVIEW_WEBSITE'] ?? '';
$fromEmail = $GLOBALS['MAIL_PREVIEW_FROM'] ?? '';
$fromName = $GLOBALS['MAIL_PREVIEW_FROM_NAME'] ?? '';
$smtpHost = $GLOBALS['MAIL_PREVIEW_MAIL_HOST'] ?? '';
$smtpUser = $GLOBALS['MAIL_PREVIEW_MAIL_USERNAME'] ?? '';
$smtpPort = $GLOBALS['MAIL_PREVIEW_MAIL_PORT'] ?? '';
$smtpEncryption = $GLOBALS['MAIL_PREVIEW_MAIL_ENCRYPTION'] ?? '';
$smtpPassword = $GLOBALS['MAIL_PREVIEW_MAIL_PASSWORD'] ?? '';
$projectStart = $GLOBALS['MAIL_PREVIEW_PROJECT_START'] ?? '';
$currentYear = $GLOBALS['MAIL_PREVIEW_CURRENT_YEAR'] ?? '';
$templateIndex = $GLOBALS['MAIL_PREVIEW_TEMPLATES_INDEX'] ?? [];
$templateLabel = $GLOBALS['MAIL_PREVIEW_TEMPLATE_LABEL'] ?? '';
$templateKey = $GLOBALS['MAIL_PREVIEW_TEMPLATE_KEY'] ?? $selectedTemplate;
/**
* Build a full state snapshot so ANY change (template or mail config)
* will change the hash and trigger a live refresh.
*/
$previewState = [
'body' => $body,
'subject' => $subject,
'to' => $to,
'username' => $username,
'domain' => $domain,
'company' => $company,
'fromName' => $fromName,
'fromEmail' => $fromEmail,
'smtpHost' => $smtpHost,
'smtpUser' => $smtpUser,
'smtpPort' => $smtpPort,
'smtpEncryption' => $smtpEncryption,
// we only care if a password exists, not the value itself
'hasSmtpPassword' => (bool) $smtpPassword,
'projectStart' => $projectStart,
'currentYear' => $currentYear,
];
$bodyHash = sha1(json_encode($previewState, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
if (isset($_GET['mode']) && $_GET['mode'] === 'json') {
header('Content-Type: application/json; charset=utf-8');
echo json_encode([
'hash' => $bodyHash,
'state' => $previewState,
], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
exit;
}
/**
* Status banner state
*/
$statusKind = null; // 'success' | 'error' | null
$statusMessage = null;
if (isset($_GET['status'])) {
if ($_GET['status'] === 'ok') {
$statusKind = 'success';
$statusMessage = "Email sent successfully to {$to}";
} elseif ($_GET['status'] === 'fail') {
$statusKind = 'error';
$statusMessage = "Failed to send email. Check error logs.";
}
}
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Mail Renderer - Xovae</title>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<link href="https://fonts.googleapis.com/css2?family=Lexend+Deca:wght@300;400;500;600;700&display=swap"
rel="stylesheet" />
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = {
theme: {
extend: {
fontFamily: {
sans: ['"Lexend Deca"', 'system-ui', 'sans-serif'],
}
}
}
}
</script>
<style>
.grid-pattern {
background-image:
linear-gradient(to right, rgba(148, 163, 184, 0.08) 1px, transparent 1px),
linear-gradient(to bottom, rgba(148, 163, 184, 0.08) 1px, transparent 1px);
background-size: 24px 24px;
}
</style>
</head>
<body class="bg-slate-50 text-slate-900 min-h-screen font-sans antialiased">
<div class="min-h-screen flex flex-col">
<header class="bg-slate-900 text-white border-b border-slate-700">
<div class="max-w-[1800px] mx-auto px-6 py-6">
<div class="flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between">
<div class="flex items-center gap-4">
<div
class="flex items-center justify-center w-12 h-12 bg-blue-600 text-white font-bold text-lg rounded-md">
<?= strtoupper(substr($domain ?: 'UD', 0, 2)) ?>
</div>
<div>
<h1 class="text-2xl font-semibold tracking-tight" id="domainTitle">
<?= htmlspecialchars($domain ?: 'MAIL PREVIEW CONSOLE') ?>
</h1>
<p class="text-xs font-medium text-slate-400 tracking-[0.18em] mt-0.5">
Mail Template Review & Delivery Workspace
</p>
</div>
</div>
<div class="flex flex-col sm:flex-row items-start sm:items-center gap-3">
<form method="get"
class="flex items-center gap-3 bg-slate-800/90 border border-slate-700 px-4 py-2.5 rounded-lg">
<label class="text-xs font-semibold text-slate-400 uppercase tracking-wider">
TEMPLATE
</label>
<div class="relative">
<select name="tpl" class="appearance-none bg-slate-700 border border-slate-600 text-white text-sm
pl-3 pr-8 py-1.5 rounded-md
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500
cursor-pointer" onchange="this.form.submit()">
<?php foreach ($templateIndex as $tpl): ?>
<option value="<?= htmlspecialchars($tpl['key']) ?>"
<?= $tpl['key'] === $templateKey ? 'selected' : '' ?>>
<?= htmlspecialchars($tpl['label']) ?>
</option>
<?php endforeach; ?>
</select>
<svg class="pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 w-4 h-4 text-slate-300"
fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M19 9l-7 7-7-7" />
</svg>
</div>
</form>
<form method="post" onsubmit="handleSendEmail(event)">
<input type="hidden" name="tpl" value="<?= htmlspecialchars($templateKey) ?>" />
<button type="submit" name="send" id="sendButton" class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2.5 rounded font-medium text-sm
transition-colors focus:outline-none focus:ring-2
focus:ring-blue-500 focus:ring-offset-2 focus:ring-offset-slate-900
flex items-center gap-2">
<svg id="sendIcon" class="w-4 h-4" fill="none" stroke="currentColor"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
</svg>
<svg id="loadingIcon" class="w-4 h-4 animate-spin hidden" fill="none"
stroke="currentColor" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke-width="4" />
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0
3.042 1.135 5.824 3 7.938l3-2.647z" />
</svg>
<span id="sendText">Send Email</span>
</button>
</form>
</div>
</div>
</div>
</header>
<?php if ($statusKind && $statusMessage): ?>
<div class="bg-white border-b border-slate-200">
<div class="max-w-[1800px] mx-auto px-6 py-3">
<div
class="flex items-center gap-3 <?= $statusKind === 'success' ? 'text-green-700' : 'text-red-700' ?>">
<div
class="flex items-center justify-center w-8 h-8 rounded-full <?= $statusKind === 'success' ? 'bg-green-100' : 'bg-red-100' ?>">
<span class="text-lg font-bold">
<?= $statusKind === 'success' ? '✓' : '✕' ?>
</span>
</div>
<p class="font-medium text-sm"><?= htmlspecialchars($statusMessage) ?></p>
</div>
</div>
</div>
<?php endif; ?>
<div class="flex-1 max-w-[1800px] mx-auto w-full px-6 py-6">
<div class="grid grid-cols-1 xl:grid-cols-[380px,minmax(0,1fr)] gap-6 h-full">
<section class="bg-white border border-slate-200 shadow-sm rounded-lg overflow-hidden flex flex-col">
<div class="bg-slate-800 text-white px-5 py-4 border-b border-slate-700">
<h2 class="font-semibold text-sm tracking-wider">
Message Configurations From .env
</h2>
</div>
<div class="flex-1 overflow-y-auto px-5 py-5 space-y-6 text-sm">
<div>
<h3
class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-3 pb-2 border-b border-slate-200">
Message Details
</h3>
<dl class="space-y-3">
<div>
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
From
</dt>
<dd class="text-slate-900">
<div class="font-medium" id="fromNameValue">
<?= htmlspecialchars($fromName ?: 'N/A') ?>
</div>
<div class="text-xs text-slate-500" id="fromEmailValue">
<?= htmlspecialchars($fromEmail ?: 'N/A') ?>
</div>
</dd>
</div>
<div>
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
To
</dt>
<dd class="text-slate-900">
<div class="font-medium" id="toNameValue">
<?= htmlspecialchars($username ?: 'User') ?>
</div>
<div class="text-xs text-slate-500" id="toEmailValue">
<?= htmlspecialchars($to ?: 'N/A') ?>
</div>
</dd>
</div>
<div>
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
Subject
</dt>
<dd class="font-medium text-slate-900" id="subjectValue">
<?= htmlspecialchars($subject) ?>
</dd>
</div>
</dl>
</div>
<div>
<h3
class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-3 pb-2 border-b border-slate-200">
Organization
</h3>
<dl class="space-y-3">
<div>
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
Domain
</dt>
<dd class="font-medium text-slate-900" id="domainValue">
<?= htmlspecialchars($domain ?: '—') ?>
</dd>
</div>
<div>
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
Company
</dt>
<dd class="font-medium text-slate-900" id="companyValue">
<?= htmlspecialchars($company ?: '—') ?>
</dd>
</div>
</dl>
</div>
<div>
<h3
class="text-xs font-semibold uppercase tracking-wider text-slate-500 mb-3 pb-2 border-slate-200 border-b">
SMTP Configuration
</h3>
<dl class="space-y-3">
<div>
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
Host
</dt>
<dd class="text-xs text-slate-900" id="smtpHostValue">
<?= htmlspecialchars($smtpHost ?: '—') ?>
</dd>
</div>
<div>
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
Username
</dt>
<dd class="text-xs text-slate-900" id="smtpUserValue">
<?= htmlspecialchars($smtpUser ?: '—') ?>
</dd>
</div>
<div>
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
Port
</dt>
<dd class="text-xs text-slate-900" id="smtpPortValue">
<?= htmlspecialchars($smtpPort ?: '—') ?>
</dd>
</div>
<div>
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
Encryption
</dt>
<dd class="text-xs text-slate-900" id="smtpEncValue">
<?= htmlspecialchars($smtpEncryption ?: '—') ?>
</dd>
</div>
<div>
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
Password
</dt>
<dd class="text-xs text-slate-500" id="smtpPwdValue">
<?= htmlspecialchars($smtpPassword ? '••••••••' : '—') ?>
</dd>
</div>
<div>
<dt class="text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">
Project Timeline
</dt>
<dd class="text-xs text-slate-900" id="projectTimelineValue">
<?php if ($projectStart && $currentYear): ?>
<?= htmlspecialchars($projectStart) ?> <?= htmlspecialchars($currentYear) ?>
<?php else: ?>
<span class="text-slate-400">—</span>
<?php endif; ?>
</dd>
</div>
</dl>
</div>
<div class="bg-slate-50 border border-slate-200 rounded p-4">
<h3 class="text-xs font-semibold uppercase tracking-wider text-slate-700 mb-2">
Documentation
</h3>
<p class="text-xs leading-relaxed text-slate-600">
Preview live-rendered HTML email templates are generated by PHPMailer.
To modify a template, edit
<code class="text-[10px] bg-white px-1.5 py-0.5 border border-slate-300 rounded">
app/mail/mailer.php
</code>
and manage template definitions in
<code class="text-[10px] bg-white px-1.5 py-0.5 border border-slate-300 rounded">
app/mail/templates/loader.php
</code>.
For more, visit
<a href="https://github.com/xodivorce/mailer-dev-console" target="_blank"
class="text-[#0f172a] hover:text-[#0f172acb] underline">
xodivorce/mailer-dev-console
</a>.
</p>
</div>
</div>
</section>
<section
class="bg-white border border-slate-200 shadow-sm rounded-lg overflow-hidden flex flex-col min-h-[700px]">
<div class="bg-slate-100 border-b border-slate-200 px-5 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<div id="livePreviewBadge"
class="flex items-center justify-center w-10 h-8 bg-slate-700 text-white text-xs rounded transition-colors duration-200">
HTML
</div>
<div>
<h2 class="font-semibold text-slate-900 text-base">
Rendering Console
</h2>
<p id="previewSubjectLine" class="text-xs text-slate-500 mt-0.5 leading-snug">
<?= htmlspecialchars($subject) ?>
</p>
</div>
</div>
<div class="flex items-center gap-2">
<span class="text-xs font-semibold text-slate-600 tracking-wider">
iFRAME RENDERING..
</span>
<span class="relative flex h-2 w-2">
<span
class="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span class="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
</span>
</div>
</div>
</div>
<div class="flex-1 grid-pattern bg-slate-50 p-2">
<iframe id="previewFrame"
class="w-full h-full bg-white border border-slate-200 rounded shadow-inner"
srcdoc="<?= htmlspecialchars($body, ENT_QUOTES, 'UTF-8') ?>"></iframe>
</div>
</section>
</div>
</div>
</div>
<script>
const MAILER_INITIAL_HASH = "<?= htmlspecialchars($bodyHash, ENT_QUOTES, 'UTF-8') ?>";
const MAILER_TPL_KEY = "<?= htmlspecialchars($templateKey, ENT_QUOTES, 'UTF-8') ?>";
const MAILER_PHP_SELF = "<?= htmlspecialchars($_SERVER['PHP_SELF'], ENT_QUOTES, 'UTF-8') ?>";
let currentHash = MAILER_INITIAL_HASH;
function handleSendEmail(event) {
const button = document.getElementById('sendButton');
const sendIcon = document.getElementById('sendIcon');
const loadingIcon = document.getElementById('loadingIcon');
const sendText = document.getElementById('sendText');
button.disabled = true;
button.classList.add('opacity-75', 'cursor-not-allowed');
button.classList.remove('hover:bg-blue-700');
sendIcon.classList.add('hidden');
loadingIcon.classList.remove('hidden');
sendText.textContent = 'Processing...';
}
function flashLivePreviewBadge() {
const badge = document.getElementById('livePreviewBadge');
if (!badge) return;
badge.classList.remove('bg-slate-700');
badge.classList.add('bg-green-600');
setTimeout(() => {
badge.classList.remove('bg-green-600');
badge.classList.add('bg-slate-700');
}, 600);
}
function setText(id, value) {
const el = document.getElementById(id);
if (el) {
el.textContent = value;
}
}
async function pollTemplateChanges() {
try {
const params = new URLSearchParams({
tpl: MAILER_TPL_KEY,
mode: 'json',
_: Date.now().toString(),
});
const res = await fetch(MAILER_PHP_SELF + '?' + params.toString(), {
cache: 'no-store',
});
if (!res.ok) throw new Error('Preview poll failed');
const data = await res.json();
if (!data || !data.hash || !data.state) return;
if (data.hash !== currentHash) {
currentHash = data.hash;
const s = data.state;
// iframe + subject
const iframe = document.getElementById('previewFrame');
const subjectLine = document.getElementById('previewSubjectLine');
if (iframe && typeof s.body === 'string') {
iframe.srcdoc = s.body;
}
if (subjectLine && typeof s.subject === 'string') {
subjectLine.textContent = s.subject || '(no subject)';
}
setText('subjectValue', s.subject || '(no subject)');
// message details
setText('fromNameValue', s.fromName || 'N/A');
setText('fromEmailValue', s.fromEmail || 'N/A');
setText('toNameValue', s.username || 'User');
setText('toEmailValue', s.to || 'N/A');
// org
setText('domainValue', s.domain || '—');
setText('companyValue', s.company || '—');
// header title domain
const domainTitle = document.getElementById('domainTitle');
if (domainTitle) {
domainTitle.textContent = s.domain || 'MAIL PREVIEW CONSOLE';
}
// smtp
setText('smtpHostValue', s.smtpHost || '—');
setText('smtpUserValue', s.smtpUser || '—');
setText('smtpPortValue', s.smtpPort || '—');
setText('smtpEncValue', s.smtpEncryption || '—');
setText('smtpPwdValue', s.hasSmtpPassword ? '••••••••' : '—');
// project timeline
const timeline = (s.projectStart && s.currentYear)
? (s.projectStart + ' ' + s.currentYear)
: '—';
setText('projectTimelineValue', timeline);
flashLivePreviewBadge();
}
} catch (err) {
// silent fail, retry
} finally {
setTimeout(pollTemplateChanges, 2000);
}
}
window.addEventListener('DOMContentLoaded', () => {
pollTemplateChanges();
});
</script>
</body>
</html>