One-shot bilingual intro paragraph with markdown + author avatar
- Admin can set a per-locale intro paragraph for the next issue on
the preferences page; cleared automatically after a successful
send. Stored in module_setting (longText) so multi-paragraph
notes fit.
- Intro is rendered via webtrees' CommonMark factory (same flavour
as notes) with raw HTML escaped, supports {{first_name}},
{{last_name}}, {{username}}, {{email}} substitution per recipient.
- Two-column intro layout: tree contact user's linked Individual
becomes the editorial portrait on the left. Their avatar is
added to the per-recipient embed set so the inline image always
resolves rather than falling through to a tree-page login link.
- Masthead now shows the tree URL under the title.
- Avatar source dimensions bumped 96→192 px and JPEG quality 75→88
so portraits stay crisp at retina display ratios.
This commit is contained in:
@@ -167,6 +167,38 @@ use Illuminate\Support\Collection;
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<fieldset class="row mb-3">
|
||||
<legend class="col-sm-3 col-form-label">
|
||||
<?= I18N::translate('Intro paragraph for the next email') ?>
|
||||
</legend>
|
||||
<div class="col-sm-9">
|
||||
<small class="form-text text-muted d-block mb-2">
|
||||
<?= I18N::translate('Shown once, above the upcoming events. Cleared automatically after the next successful send.') ?>
|
||||
<br>
|
||||
<?= I18N::translate('Formatted as Markdown — e.g. %1$s for emphasis, %2$s for a link.', '<code>**bold**</code>', '<code>[label](https://example.org)</code>') ?>
|
||||
<br>
|
||||
<?= I18N::translate('Personalisation tokens:') ?>
|
||||
<code>{{first_name}}</code>,
|
||||
<code>{{last_name}}</code>,
|
||||
<code>{{username}}</code>,
|
||||
<code>{{email}}</code>
|
||||
</small>
|
||||
<?php foreach (Configuration::supportedSubjectLocales() as $code => $label) : ?>
|
||||
<?php
|
||||
$field = 'intro-' . $id . '-' . $code;
|
||||
$val = Configuration::introForLocale($module, $tree, $code);
|
||||
?>
|
||||
<div class="mb-2">
|
||||
<label class="form-label small text-muted mb-1" for="<?= e($field) ?>">
|
||||
<?= e($label) ?>
|
||||
</label>
|
||||
<textarea class="form-control" rows="6"
|
||||
id="<?= e($field) ?>" name="<?= e($field) ?>"><?= e($val) ?></textarea>
|
||||
</div>
|
||||
<?php endforeach ?>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div class="row mb-3">
|
||||
<label class="col-sm-3 col-form-label">
|
||||
<?= I18N::translate('Subscribed users') ?>
|
||||
|
||||
@@ -5,8 +5,10 @@ declare(strict_types=1);
|
||||
use Fisharebest\Webtrees\Date;
|
||||
use Fisharebest\Webtrees\Fact;
|
||||
use Fisharebest\Webtrees\Family;
|
||||
use Fisharebest\Webtrees\Http\RequestHandlers\TreePage;
|
||||
use Fisharebest\Webtrees\I18N;
|
||||
use Fisharebest\Webtrees\Individual;
|
||||
use Fisharebest\Webtrees\Registry;
|
||||
use Fisharebest\Webtrees\Tree;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
@@ -22,6 +24,8 @@ use Illuminate\Support\Collection;
|
||||
* @var array<string,string> $relationships xref => "your mother" etc. (per-recipient)
|
||||
* @var array<string,true> $detailed_xrefs xref-set — render in detail; others as summary bullet
|
||||
* @var string $account_url
|
||||
* @var string $intro Admin-supplied one-shot intro paragraph; "" = skip block
|
||||
* @var Individual|null $intro_author Tree contact's linked record, if any — avatar source for the intro
|
||||
*/
|
||||
|
||||
// ─── BockenTheme light-mode palette ─────────────────────────────────────
|
||||
@@ -592,7 +596,20 @@ $timeline_arrow_row = '<tr>'
|
||||
<h1 style="margin:10px 0 6px;font-weight:300;font-size:38px;line-height:1.1;letter-spacing:-0.015em;color:<?= $palette['ink'] ?>;">
|
||||
<?= e($tree->title()) ?>
|
||||
</h1>
|
||||
<div style="font-size:13px;font-weight:300;color:<?= $palette['ink3'] ?>;">
|
||||
<?php
|
||||
// Strip the leading scheme so the link
|
||||
// reads as a clean hostname/path — the
|
||||
// anchor still points at the absolute URL.
|
||||
$tree_url = route(TreePage::class, ['tree' => $tree->name()]);
|
||||
$tree_url_lbl = preg_replace('~^https?://~i', '', rtrim($tree_url, '/'));
|
||||
?>
|
||||
<div style="margin-top:4px;font-size:13px;font-weight:400;letter-spacing:0.01em;">
|
||||
<a href="<?= e($tree_url) ?>"
|
||||
style="color:<?= $palette['link'] ?>;text-decoration:none;border-bottom:1px solid <?= $palette['link'] ?>33;">
|
||||
<?= e($tree_url_lbl) ?>
|
||||
</a>
|
||||
</div>
|
||||
<div style="margin-top:6px;font-size:13px;font-weight:300;color:<?= $palette['ink3'] ?>;">
|
||||
<?= e($masthead_date($generated_at)) ?>
|
||||
<span style="color:<?= $palette['mute'] ?>;">·</span>
|
||||
<?= e(I18N::translate('Events in the next %d days.', $window_days)) ?>
|
||||
@@ -600,6 +617,40 @@ $timeline_arrow_row = '<tr>'
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<?php if (trim($intro) !== '') : ?>
|
||||
<!-- Editorial: one-shot intro paragraph ──────────── -->
|
||||
<?php
|
||||
// Render via webtrees' Markdown factory: CommonMark
|
||||
// with autolinks, the same flavour used elsewhere
|
||||
// in the site. Raw HTML in the source is escaped
|
||||
// by the factory's HtmlFilter::ESCAPE setting, so
|
||||
// a stray "<" can't break the email layout.
|
||||
$intro_html = Registry::markdownFactory()->markdown(trim($intro), $tree);
|
||||
$intro_inner = '<div style="border-left:3px solid ' . $palette['accent'] . ';padding:6px 0 6px 16px;'
|
||||
. 'font-size:15px;line-height:1.55;font-weight:300;color:' . $palette['ink'] . ';'
|
||||
. 'font-style:italic;">' . $intro_html . '</div>';
|
||||
?>
|
||||
<tr>
|
||||
<td style="padding:0 8px 24px;">
|
||||
<?php if ($intro_author instanceof Individual) : ?>
|
||||
<table role="presentation" cellpadding="0" cellspacing="0" border="0"
|
||||
style="width:100%;border-collapse:collapse;">
|
||||
<tr>
|
||||
<td style="width:72px;vertical-align:top;padding-top:4px;">
|
||||
<?= $avatar($intro_author) ?>
|
||||
</td>
|
||||
<td style="vertical-align:top;">
|
||||
<?= $intro_inner ?>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<?php else : ?>
|
||||
<?= $intro_inner ?>
|
||||
<?php endif ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (!$birthdays->isEmpty()) : ?>
|
||||
<?php
|
||||
$detailed = [];
|
||||
|
||||
Reference in New Issue
Block a user