Initial baseline: LaraBlog core with plugin commerce surface.

Captures the current working tree after theme slots, ArticleAccess, and the payment / paid-content plugins so subsequent work has a reviewable git history.
This commit is contained in:
ak
2026-08-12 01:15:38 +08:00
commit 263b98b218
337 changed files with 31393 additions and 0 deletions
+41
View File
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace App\Domain\Blog;
use Mews\Purifier\Facades\Purifier;
class HtmlTeaser
{
/**
* Build a teaser from already-rendered HTML.
*
* The result is always a plain-text excerpt and always withholds part of the
* body: when the configured limit covers the whole article we still cut it
* in half, so a gated article can never be served in full through a teaser.
*/
public function truncate(string $html, int $maxChars): string
{
if ($maxChars <= 0 || trim($html) === '') {
return '';
}
$text = html_entity_decode(strip_tags($html), ENT_QUOTES | ENT_HTML5, 'UTF-8');
$text = trim(preg_replace('/\s+/u', ' ', $text) ?? '');
if ($text === '') {
return '';
}
$length = mb_strlen($text);
$limit = min($maxChars, max(1, (int) floor($length / 2)));
$snippet = mb_substr($text, 0, $limit);
if ($limit < $length) {
$snippet .= '…';
}
return Purifier::clean('<p>'.e($snippet).'</p>', 'article');
}
}