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
+27
View File
@@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class AiSettings extends Settings
{
public string $provider;
public ?string $api_base_url;
public ?string $api_key;
public ?string $model;
public bool $comment_moderation_enabled;
public bool $content_optimization_enabled;
public static function group(): string
{
return 'ai';
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class BlogSettings extends Settings
{
public int $posts_per_page;
public bool $allow_comments;
public string $comment_order;
public bool $show_views;
public bool $show_author;
public string $date_format;
public bool $close_comments_on_old_posts;
public int $close_comments_days;
public static function group(): string
{
return 'blog';
}
}
+25
View File
@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class CommentSettings extends Settings
{
public bool $guest_can_comment;
public bool $require_moderation;
public int $rate_limit_per_minute;
public bool $enable_website_field;
public string $forbidden_words;
public static function group(): string
{
return 'comment';
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class GeneralSettings extends Settings
{
public string $site_name;
public string $site_url;
public ?string $site_description;
public string $active_theme;
public string $attachments_url_prefix;
/** @var 'html'|'markdown' Default format for newly created articles */
public string $default_content_format;
/** @var 'html'|'markdown' Format written during sablog import when not converting */
public string $import_content_format;
/** When true, import converts HTML bodies to Markdown */
public bool $import_convert_html_to_markdown;
public static function group(): string
{
return 'general';
}
}
+29
View File
@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace App\Settings;
use Spatie\LaravelSettings\Settings;
class SeoSettings extends Settings
{
public ?string $meta_title_suffix;
public ?string $default_description;
public ?string $default_keywords;
public bool $json_ld_enabled;
public bool $robots_index;
public ?string $twitter_site;
public bool $canonical_force_https;
public static function group(): string
{
return 'seo';
}
}
+59
View File
@@ -0,0 +1,59 @@
<?php
declare(strict_types=1);
namespace App\Settings;
use App\Domain\Theme\ThemeSlot;
use Spatie\LaravelSettings\Settings;
class SnippetSettings extends Settings
{
/** Analytics / tags in <head> */
public string $analytics_head;
/** Extra HTML/JS before </body> */
public string $body_end;
/** Ad / promo HTML in sidebar */
public string $ads_sidebar;
/** Ad above article body */
public string $ads_article_top;
/** Ad below article body */
public string $ads_article_bottom;
/** Free HTML after header / before main */
public string $header_banner;
/** Temporary links / notices in sidebar (HTML allowed) */
public string $custom_links_html;
/** Footer free HTML */
public string $footer_html;
public static function group(): string
{
return 'snippets';
}
/**
* Map settings fields ThemeSlot names.
*
* @return array<string, string>
*/
public function slotMap(): array
{
return [
ThemeSlot::HEAD => $this->analytics_head,
ThemeSlot::BODY_END => $this->body_end,
ThemeSlot::SIDEBAR => $this->ads_sidebar,
ThemeSlot::ARTICLE_TOP => $this->ads_article_top,
ThemeSlot::ARTICLE_BOTTOM => $this->ads_article_bottom,
ThemeSlot::HEADER_AFTER => $this->header_banner,
ThemeSlot::SIDEBAR_AFTER => $this->custom_links_html,
ThemeSlot::FOOTER_BEFORE => $this->footer_html,
];
}
}