fix: restyle pager chips and restore theme ad slots
Replace the loose page-count label with a SaBlog-style 6 / 316 chip, wire inject/stylevar HTML into list and post views, and flush page cache when ads are saved. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
|
||||
## 2026-09-18
|
||||
|
||||
- Pager chip is now `6 / 316` in the old SaBlog bar style, not a loose “第 x / y 页” label.
|
||||
- Theme inject stacks cover list/content/footer; stylevars and leftover HTML ads render. Saving inject flushes page cache. `sablog:import` copies `stylevars`.
|
||||
- Schema snapshot: `docs/database/mysql-schema-20260918-214145.sql`.
|
||||
- Homepage / lists have SaBlog-style **标准 | 列表** browse modes (`home_view_mode`, `?view=`, cookie).
|
||||
- Pagination is compact (`第 x / y 页` + fewer page chips) and the content column uses CSS grid so it no longer sits under the sidebar.
|
||||
- Imported SaBlog HTML no longer shows literal ` `; highlighter / stacked docker `<div>` blocks become wrapped `<pre><code>`.
|
||||
|
||||
+8
-1
@@ -61,11 +61,18 @@ See `README.md` and `docs/` for install, import, plugins, and themes.
|
||||
|
||||
## Pagination and imported HTML
|
||||
|
||||
- Public pagers use `onEachSide(1)` plus “第 x / y 页”, and the main column is CSS grid `minmax(0, 1fr)` so page chips stay in the content column.
|
||||
- Public pagers use `onEachSide(1)` plus a compact `6 / 316` chip (old SaBlog `.p_bar` look), and the main column is CSS grid `minmax(0, 1fr)` so page chips stay in the content column.
|
||||
- `SablogHtmlNormalizer` strips leftover ` `, turns SyntaxHighlighter `codeText` / `dp-*` lists into `<pre><code>`, and wraps stacked docker/shell `<div>` lines.
|
||||
- Render path always normalizes, so already-imported posts look right without rewriting the database. Persist with `php artisan sablog:fix-content --all`.
|
||||
- Code blocks wrap / scroll inside the column instead of stretching the page.
|
||||
|
||||
## Theme ads / inject
|
||||
|
||||
- All list and post views include `content_top` / `content_bottom` (and post body) stacks. Saving **主题注入** flushes page cache.
|
||||
- Theme variables (old stylevars) render automatically: `ad_header` → header, leftover HTML vars such as `huangjinlian` → footer.
|
||||
- `sablog:import` now copies the old `stylevars` table into `theme_vars_{theme}`.
|
||||
- Do not add a third half-finished skin. Tighten `sablog` to match the old site; a new theme is a later, complete job.
|
||||
|
||||
## Media library (xpier)
|
||||
|
||||
- Package: `xpier/filament-media-library` (admin Media Library + MediaPicker).
|
||||
|
||||
@@ -67,7 +67,7 @@ php artisan sablog:fix-content --all
|
||||
S3_ACCESS_KEY=... S3_BUCKET=... S3_ENDPOINT=... php artisan attachments:sync-s3 --legacy-dir=/path/to/old/attachments
|
||||
```
|
||||
|
||||
> 不迁移的过时功能:trackback(引用通告,垃圾来源)、搜索缓存表、验证码(由 AI 审核 + 蜜罐 + 频控取代)、WAP、广告位变量。
|
||||
> 不迁移的过时功能:trackback(引用通告,垃圾来源)、搜索缓存表、验证码(由 AI 审核 + 蜜罐 + 频控取代)、WAP。老广告位 `stylevars` 会导入为当前主题变量并在对应注入点显示。
|
||||
|
||||
## 主题
|
||||
|
||||
|
||||
@@ -34,6 +34,24 @@ class ThemeInjector
|
||||
'body_end' => '页面末尾(</body> 前)',
|
||||
];
|
||||
|
||||
/**
|
||||
* Old SaBlog stylevar names → inject points. Unmapped HTML vars go to footer.
|
||||
*
|
||||
* @var array<string, list<string>>
|
||||
*/
|
||||
public const STYLEVAR_POINTS = [
|
||||
'head' => ['ad_head', 'headad'],
|
||||
'header' => ['headerad', 'header_ad', 'ad_header', 'topad', 'ad_top', 'sitead', 'site_ad'],
|
||||
'sidebar_top' => ['sidebarad', 'sidebar_ad', 'ad_sidebar', 'leftad', 'ad_left'],
|
||||
'sidebar_bottom' => ['ad_sidebar_bottom'],
|
||||
'content_top' => ['indexad', 'ad_index', 'contentad', 'ad_content'],
|
||||
'content_bottom' => ['ad_content_bottom'],
|
||||
'post_content_top' => ['ad_post_top', 'insad'],
|
||||
'post_content_bottom' => ['ad_post_bottom'],
|
||||
'footer' => ['footerad', 'footer_ad', 'ad_footer', 'huangjinlian', 'huangjinlian2', 'huangjinlian3'],
|
||||
'body_end' => ['ad_body_end'],
|
||||
];
|
||||
|
||||
/**
|
||||
* 读取某一注入点的所有注入块(多条,已排序、已过滤停用),
|
||||
* 并把插件追加的 HTML 合并进来。
|
||||
@@ -51,6 +69,10 @@ class ThemeInjector
|
||||
->values()
|
||||
->all();
|
||||
|
||||
foreach (self::stylevarBlocks($point) as $html) {
|
||||
$blocks[] = $html;
|
||||
}
|
||||
|
||||
$extra = (string) app(PluginManager::class)->applyFilters("theme.inject.{$point}", '');
|
||||
|
||||
if ($extra !== '') {
|
||||
@@ -75,4 +97,45 @@ class ThemeInjector
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private static function stylevarBlocks(string $point): array
|
||||
{
|
||||
$vars = app(ThemeManager::class)->variables();
|
||||
if ($vars === []) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$html = [];
|
||||
foreach (self::STYLEVAR_POINTS[$point] ?? [] as $key) {
|
||||
$value = trim((string) ($vars[$key] ?? ''));
|
||||
if ($value !== '') {
|
||||
$html[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($point !== 'footer') {
|
||||
return $html;
|
||||
}
|
||||
|
||||
$mapped = [];
|
||||
foreach (self::STYLEVAR_POINTS as $keys) {
|
||||
foreach ($keys as $key) {
|
||||
$mapped[$key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($vars as $key => $value) {
|
||||
$value = trim((string) $value);
|
||||
if ($value === '' || isset($mapped[$key]) || ! str_contains($value, '<')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$html[] = $value;
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ class SablogImport extends Command
|
||||
}
|
||||
|
||||
$this->importSettings();
|
||||
$this->importStylevars();
|
||||
$this->importCategories();
|
||||
$this->importUsers();
|
||||
$this->importPosts();
|
||||
@@ -144,7 +145,7 @@ class SablogImport extends Command
|
||||
* searchindex —— 搜索缓存,现代 SQL 全文检索足够
|
||||
* sessions —— Laravel 原生会话
|
||||
* statistics —— 实时统计
|
||||
* stylevars —— 老式广告位变量
|
||||
* stylevars —— 导入为当前主题的 theme_vars(广告位)
|
||||
* seccode / 验证码 —— 由 AI 审核 + 蜜罐 + 频控取代
|
||||
*/
|
||||
private function importSettings(): void
|
||||
@@ -182,6 +183,34 @@ class SablogImport extends Command
|
||||
$this->report['settings'] = $count;
|
||||
}
|
||||
|
||||
private function importStylevars(): void
|
||||
{
|
||||
if (! $this->hasTable('stylevars')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$vars = [];
|
||||
foreach ($this->rows('stylevars') as $row) {
|
||||
$name = (string) ($row['title'] ?? $row['variable'] ?? $row['name'] ?? '');
|
||||
$value = (string) ($row['value'] ?? $row['content'] ?? '');
|
||||
if ($name === '' || $value === '') {
|
||||
continue;
|
||||
}
|
||||
$vars[$name] = $value;
|
||||
}
|
||||
|
||||
if ($vars === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$theme = (string) Setting::get('active_theme', 'sablog');
|
||||
$existing = Setting::get('theme_vars_'.$theme, []);
|
||||
$existing = is_array($existing) ? $existing : (json_decode((string) $existing, true) ?: []);
|
||||
|
||||
Setting::set('theme_vars_'.$theme, array_merge($existing, $vars));
|
||||
$this->report['stylevars'] = count($vars);
|
||||
}
|
||||
|
||||
private function importCategories(): void
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
@@ -119,6 +119,7 @@ class ThemeInject extends Page
|
||||
|
||||
Setting::set('inject.blocks', $blocks);
|
||||
Setting::set('theme_vars_'.app(ThemeManager::class)->active(), $data['theme_vars'] ?? []);
|
||||
\App\Blog\Support\PageCacheMiddleware::flush();
|
||||
|
||||
Notification::make()->title('注入内容已保存')->success()->send();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,584 @@
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
DROP TABLE IF EXISTS `cache`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `cache` (
|
||||
`key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`value` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`expiration` int NOT NULL,
|
||||
PRIMARY KEY (`key`),
|
||||
KEY `cache_expiration_index` (`expiration`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `cache_locks`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `cache_locks` (
|
||||
`key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`owner` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`expiration` int NOT NULL,
|
||||
PRIMARY KEY (`key`),
|
||||
KEY `cache_locks_expiration_index` (`expiration`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `categories`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `categories` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`slug` varchar(120) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`display_order` tinyint NOT NULL DEFAULT '0',
|
||||
`description` text COLLATE utf8mb4_unicode_ci,
|
||||
`cover_media_id` bigint unsigned DEFAULT NULL,
|
||||
`post_count` int unsigned NOT NULL DEFAULT '0',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `categories_slug_unique` (`slug`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `comments`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `comments` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`post_id` bigint unsigned NOT NULL,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`author_name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`author_email` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`author_url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`content` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`ip` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending',
|
||||
`ai_review` json DEFAULT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `comments_user_id_foreign` (`user_id`),
|
||||
KEY `comments_post_id_status_index` (`post_id`,`status`),
|
||||
KEY `comments_status_index` (`status`),
|
||||
CONSTRAINT `comments_post_id_foreign` FOREIGN KEY (`post_id`) REFERENCES `posts` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `comments_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `failed_jobs`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `failed_jobs` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`uuid` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`connection` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`queue` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`exception` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`failed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `failed_jobs_uuid_unique` (`uuid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `hello_world_logs`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `hello_world_logs` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`comment_id` bigint unsigned DEFAULT NULL,
|
||||
`note` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `hello_world_logs_comment_id_foreign` (`comment_id`),
|
||||
CONSTRAINT `hello_world_logs_comment_id_foreign` FOREIGN KEY (`comment_id`) REFERENCES `comments` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `job_batches`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `job_batches` (
|
||||
`id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`total_jobs` int NOT NULL,
|
||||
`pending_jobs` int NOT NULL,
|
||||
`failed_jobs` int NOT NULL,
|
||||
`failed_job_ids` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`options` mediumtext COLLATE utf8mb4_unicode_ci,
|
||||
`cancelled_at` int DEFAULT NULL,
|
||||
`created_at` int NOT NULL,
|
||||
`finished_at` int DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `jobs`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `jobs` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`queue` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`attempts` tinyint unsigned NOT NULL,
|
||||
`reserved_at` int unsigned DEFAULT NULL,
|
||||
`available_at` int unsigned NOT NULL,
|
||||
`created_at` int unsigned NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `jobs_queue_index` (`queue`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `links`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `links` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`url` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`note` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`display_order` tinyint NOT NULL DEFAULT '0',
|
||||
`visible` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `market_packages`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `market_packages` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`item_key` varchar(190) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`item_type` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`price` bigint unsigned NOT NULL,
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending',
|
||||
`payment_id` bigint unsigned DEFAULT NULL,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `market_packages_item_key_item_type_unique` (`item_key`,`item_type`),
|
||||
KEY `market_packages_payment_id_foreign` (`payment_id`),
|
||||
KEY `market_packages_user_id_foreign` (`user_id`),
|
||||
CONSTRAINT `market_packages_payment_id_foreign` FOREIGN KEY (`payment_id`) REFERENCES `payments` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `market_packages_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `media`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `media` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`model_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`model_id` bigint unsigned NOT NULL,
|
||||
`uuid` char(36) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`collection_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`file_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`mime_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`disk` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`conversions_disk` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`size` bigint unsigned NOT NULL,
|
||||
`manipulations` json NOT NULL,
|
||||
`custom_properties` json NOT NULL,
|
||||
`generated_conversions` json NOT NULL,
|
||||
`responsive_images` json NOT NULL,
|
||||
`order_column` int unsigned DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `media_uuid_unique` (`uuid`),
|
||||
KEY `media_model_type_model_id_index` (`model_type`,`model_id`),
|
||||
KEY `media_order_column_index` (`order_column`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `media_folders`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `media_folders` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`parent_id` bigint unsigned DEFAULT NULL,
|
||||
`code` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`sort` int NOT NULL DEFAULT '0',
|
||||
`is_active` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `media_folders_code_unique` (`code`),
|
||||
KEY `media_folders_parent_id_foreign` (`parent_id`),
|
||||
CONSTRAINT `media_folders_parent_id_foreign` FOREIGN KEY (`parent_id`) REFERENCES `media_folders` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `media_library`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `media_library` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`disk` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'public',
|
||||
`path` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`original_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`extension` varchar(20) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`mime_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`size` bigint unsigned NOT NULL DEFAULT '0',
|
||||
`type` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'image',
|
||||
`source` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'admin',
|
||||
`folder` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`alt_text` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`custom_properties` json DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
`deleted_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `media_library_path_unique` (`path`),
|
||||
KEY `media_library_user_id_foreign` (`user_id`),
|
||||
KEY `media_library_type_index` (`type`),
|
||||
KEY `media_library_folder_index` (`folder`),
|
||||
KEY `media_library_source_index` (`source`),
|
||||
CONSTRAINT `media_library_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `membership_plans`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `membership_plans` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`slug` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`description` text COLLATE utf8mb4_unicode_ci,
|
||||
`price` bigint unsigned NOT NULL,
|
||||
`duration_days` int unsigned NOT NULL DEFAULT '30',
|
||||
`permissions` json DEFAULT NULL,
|
||||
`active` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`sort` int unsigned NOT NULL DEFAULT '0',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `membership_plans_slug_unique` (`slug`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `migrations`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `migrations` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||
`migration` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`batch` int NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `model_has_permissions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `model_has_permissions` (
|
||||
`permission_id` bigint unsigned NOT NULL,
|
||||
`model_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`model_id` bigint unsigned NOT NULL,
|
||||
PRIMARY KEY (`permission_id`,`model_id`,`model_type`),
|
||||
KEY `model_has_permissions_model_id_model_type_index` (`model_id`,`model_type`),
|
||||
CONSTRAINT `model_has_permissions_permission_id_foreign` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `model_has_roles`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `model_has_roles` (
|
||||
`role_id` bigint unsigned NOT NULL,
|
||||
`model_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`model_id` bigint unsigned NOT NULL,
|
||||
PRIMARY KEY (`role_id`,`model_id`,`model_type`),
|
||||
KEY `model_has_roles_model_id_model_type_index` (`model_id`,`model_type`),
|
||||
CONSTRAINT `model_has_roles_role_id_foreign` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `password_reset_tokens`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `password_reset_tokens` (
|
||||
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`token` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`email`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `payments`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `payments` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`order_no` varchar(40) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`subject` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`description` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`amount` bigint unsigned NOT NULL,
|
||||
`channel` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'alipay',
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending',
|
||||
`gateway_trade_no` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`payload` json DEFAULT NULL,
|
||||
`paid_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
`payable_type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`payable_id` bigint unsigned DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `payments_order_no_unique` (`order_no`),
|
||||
KEY `payments_user_id_status_index` (`user_id`,`status`),
|
||||
KEY `payments_payable_type_payable_id_index` (`payable_type`,`payable_id`),
|
||||
CONSTRAINT `payments_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `permissions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `permissions` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`guard_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `permissions_name_guard_name_unique` (`name`,`guard_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `personal_access_tokens`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `personal_access_tokens` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`tokenable_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`tokenable_id` bigint unsigned NOT NULL,
|
||||
`name` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`token` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`abilities` text COLLATE utf8mb4_unicode_ci,
|
||||
`last_used_at` timestamp NULL DEFAULT NULL,
|
||||
`expires_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `personal_access_tokens_token_unique` (`token`),
|
||||
KEY `personal_access_tokens_tokenable_type_tokenable_id_index` (`tokenable_type`,`tokenable_id`),
|
||||
KEY `personal_access_tokens_expires_at_index` (`expires_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `plugin_records`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `plugin_records` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`vendor` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`name` varchar(60) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`version` varchar(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`enabled` tinyint(1) NOT NULL DEFAULT '1',
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `plugin_records_vendor_name_unique` (`vendor`,`name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `posts`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `posts` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`category_id` bigint unsigned DEFAULT NULL,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`title` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`slug` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`excerpt` text COLLATE utf8mb4_unicode_ci,
|
||||
`content` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`content_format` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'markdown',
|
||||
`keywords` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`cover_media_id` bigint unsigned DEFAULT NULL,
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'published',
|
||||
`is_sticky` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`sticky_level` tinyint unsigned NOT NULL DEFAULT '0',
|
||||
`close_comment` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`read_password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`views` bigint unsigned NOT NULL DEFAULT '0',
|
||||
`comment_count` int unsigned NOT NULL DEFAULT '0',
|
||||
`meta` json DEFAULT NULL,
|
||||
`published_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `posts_slug_unique` (`slug`),
|
||||
KEY `posts_category_id_foreign` (`category_id`),
|
||||
KEY `posts_user_id_foreign` (`user_id`),
|
||||
KEY `posts_status_published_at_index` (`status`,`published_at`),
|
||||
KEY `posts_status_index` (`status`),
|
||||
KEY `posts_published_at_index` (`published_at`),
|
||||
CONSTRAINT `posts_category_id_foreign` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `posts_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `redirects`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `redirects` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`hash` varchar(16) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`target_url` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`clicks` bigint unsigned NOT NULL DEFAULT '0',
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'active',
|
||||
`last_clicked_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `redirects_hash_unique` (`hash`),
|
||||
KEY `redirects_target_url_index` (`target_url`(191))
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `role_has_permissions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `role_has_permissions` (
|
||||
`permission_id` bigint unsigned NOT NULL,
|
||||
`role_id` bigint unsigned NOT NULL,
|
||||
PRIMARY KEY (`permission_id`,`role_id`),
|
||||
KEY `role_has_permissions_role_id_foreign` (`role_id`),
|
||||
CONSTRAINT `role_has_permissions_permission_id_foreign` FOREIGN KEY (`permission_id`) REFERENCES `permissions` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `role_has_permissions_role_id_foreign` FOREIGN KEY (`role_id`) REFERENCES `roles` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `roles`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `roles` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`guard_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `roles_name_guard_name_unique` (`name`,`guard_name`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `sessions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `sessions` (
|
||||
`id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`user_id` bigint unsigned DEFAULT NULL,
|
||||
`ip_address` varchar(45) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`user_agent` text COLLATE utf8mb4_unicode_ci,
|
||||
`payload` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`last_activity` int NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `sessions_user_id_index` (`user_id`),
|
||||
KEY `sessions_last_activity_index` (`last_activity`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `settings`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `settings` (
|
||||
`key` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`value` text COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `subscriptions`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `subscriptions` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`user_id` bigint unsigned NOT NULL,
|
||||
`membership_plan_id` bigint unsigned DEFAULT NULL,
|
||||
`status` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'active',
|
||||
`starts_at` timestamp NULL DEFAULT NULL,
|
||||
`ends_at` timestamp NULL DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `subscriptions_membership_plan_id_foreign` (`membership_plan_id`),
|
||||
KEY `subscriptions_user_id_status_index` (`user_id`,`status`),
|
||||
CONSTRAINT `subscriptions_membership_plan_id_foreign` FOREIGN KEY (`membership_plan_id`) REFERENCES `membership_plans` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `subscriptions_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `taggables`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `taggables` (
|
||||
`tag_id` bigint unsigned NOT NULL,
|
||||
`taggable_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`taggable_id` bigint unsigned NOT NULL,
|
||||
UNIQUE KEY `taggables_tag_id_taggable_id_taggable_type_unique` (`tag_id`,`taggable_id`,`taggable_type`),
|
||||
KEY `taggables_taggable_type_taggable_id_index` (`taggable_type`,`taggable_id`),
|
||||
CONSTRAINT `taggables_tag_id_foreign` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `tags`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `tags` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` json NOT NULL,
|
||||
`slug` json NOT NULL,
|
||||
`type` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`order_column` int DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
DROP TABLE IF EXISTS `users`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!50503 SET character_set_client = utf8mb4 */;
|
||||
CREATE TABLE `users` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`email` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`email_verified_at` timestamp NULL DEFAULT NULL,
|
||||
`password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`remember_token` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`created_at` timestamp NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NULL DEFAULT NULL,
|
||||
`legacy_md5` varchar(32) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`url` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`logincount` int unsigned NOT NULL DEFAULT '0',
|
||||
`loginip` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`regip` varchar(64) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`logintime` timestamp NULL DEFAULT NULL,
|
||||
`lastpost_at` timestamp NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `users_email_unique` (`email`),
|
||||
KEY `users_legacy_md5_index` (`legacy_md5`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (1,'0001_01_01_000000_create_users_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (2,'0001_01_01_000001_create_cache_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (3,'0001_01_01_000002_create_jobs_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (4,'2026_08_11_092446_create_permission_tables',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (5,'2026_08_11_092448_create_media_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (6,'2026_08_11_092449_create_tag_tables',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (7,'2026_08_11_100000_create_membership_tables',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (8,'2026_08_11_100000_create_payments_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (9,'2026_08_11_100001_create_categories_and_posts_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (10,'2026_08_11_100002_create_comments_and_trackbacks_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (11,'2026_08_11_100003_create_links_and_settings_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (12,'2026_08_11_100004_add_blog_columns_to_users_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (13,'2026_08_11_100005_add_content_format_to_posts_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (14,'2026_08_11_113537_create_personal_access_tokens_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (15,'2026_08_12_000000_create_hello_world_logs_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (16,'2026_08_12_100000_add_payable_to_payments_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (17,'2026_08_12_200000_create_market_packages_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (18,'2026_08_12_300000_add_description_to_categories_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (19,'2026_08_12_400000_create_redirects_table',1);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (20,'2026_08_15_000001_create_media_library_table',2);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (21,'2026_08_15_000002_create_media_folders_table',2);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (22,'2026_08_15_000003_add_soft_deletes_to_media_library_table',2);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (23,'2026_08_15_000004_add_custom_properties_to_media_library_table',2);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (24,'2026_09_16_000001_add_cover_media_id_to_posts_and_categories',2);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (25,'2026_09_16_000002_seed_default_media_folders',2);
|
||||
INSERT INTO `migrations` (`id`, `migration`, `batch`) VALUES (26,'2026_09_18_210000_add_sticky_level_to_posts_table',3);
|
||||
@@ -83,6 +83,7 @@ routes/web.php # 前台规范路由;routes/legacy.php 老 URL 301(新增
|
||||
- 前台 RSS / Sitemap / llms.txt 开新窗口。`/llms.txt` 和 `/posts/{slug}.md` 是核心路由,不要做成静态文件,新文章要马上出现
|
||||
- 首页浏览模式:`home_view_mode` + `?view=list|full` + cookie `ll_home_view`。分页用 `blog_paginate()`(`onEachSide(1)`)
|
||||
- 老 sablog 正文清洗放 `SablogHtmlNormalizer`,导入 / 渲染 / `sablog:fix-content` 共用,不要各写一套 strip_tags
|
||||
- 广告位用 `partials.theme-inject`。保存主题注入要清页面缓存。stylevars 跟 `theme_vars_{theme}` 走,不要再忽略这张表
|
||||
|
||||
## 9. 常用命令速查
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ php artisan sablog:import \
|
||||
| `links` | `links` | linkid 保留 |
|
||||
| `attachments` | medialibrary `media` | 文件 + `legacy_attachmentid` 映射(老 `[attach=xx]` 按此解析) |
|
||||
| `settings` | `settings` | 键值映射为站点设置(可在后台「博客设置」继续改) |
|
||||
| `stylevars` | `theme_vars_{theme}` | 老广告位变量,按位置打到主题注入点 |
|
||||
| `tags` | spatie tags | 老 aids 文本解析为独立标签 + 关联 |
|
||||
|
||||
**不迁移**:trackback/引用通告(垃圾来源,接口已关闭)、搜索缓存表、验证码(由 AI 审核 + 蜜罐 + 频控取代)。
|
||||
|
||||
+41
-29
@@ -23,7 +23,18 @@ themes/{name}/
|
||||
"description": "主题描述",
|
||||
"author": "作者",
|
||||
"screenshot": "screenshot.png",
|
||||
"inject_points": ["head", "header", "sidebar_top", "sidebar_bottom", "content_top", "content_bottom", "post_content_top", "post_content_bottom", "footer", "body_end"]
|
||||
"inject_points": [
|
||||
"head",
|
||||
"header",
|
||||
"sidebar_top",
|
||||
"sidebar_bottom",
|
||||
"content_top",
|
||||
"content_bottom",
|
||||
"post_content_top",
|
||||
"post_content_bottom",
|
||||
"footer",
|
||||
"body_end"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -69,21 +80,21 @@ themes/{name}/
|
||||
|
||||
## 页面视图清单(控制器会传的数据)
|
||||
|
||||
| 视图 | 控制器 | 变量 |
|
||||
|------|--------|------|
|
||||
| `index` | HomeController | `$posts`(分页) |
|
||||
| `show` | PostController | `$post, $comments, $contentHtml` |
|
||||
| `list` | Category/Archive | `$posts, $category? / $archiveTitle?` |
|
||||
| `archives` | ArchiveController | `$archives` |
|
||||
| `tags` | TagController | `$tags` |
|
||||
| `tag` | TagController | `$tag, $posts` |
|
||||
| `search` | SearchController | `$posts, $keyword` |
|
||||
| `links` | LinkController | `$links` |
|
||||
| `comments` | CommentController | `$comments` |
|
||||
| `login` / `register` / `profile` | AuthController | — |
|
||||
| `membership.index` / `membership.mine` | 会员插件 | `$plans / $subscriptions` |
|
||||
| `membership.paywall` / `membership.paid-teaser` | 会员插件(付费墙) | `$post` |
|
||||
| `payments.sandbox` / `payments.result` | 支付插件 | `$payment` |
|
||||
| 视图 | 控制器 | 变量 |
|
||||
| ----------------------------------------------- | ------------------ | ------------------------------------- |
|
||||
| `index` | HomeController | `$posts`(分页) |
|
||||
| `show` | PostController | `$post, $comments, $contentHtml` |
|
||||
| `list` | Category/Archive | `$posts, $category? / $archiveTitle?` |
|
||||
| `archives` | ArchiveController | `$archives` |
|
||||
| `tags` | TagController | `$tags` |
|
||||
| `tag` | TagController | `$tag, $posts` |
|
||||
| `search` | SearchController | `$posts, $keyword` |
|
||||
| `links` | LinkController | `$links` |
|
||||
| `comments` | CommentController | `$comments` |
|
||||
| `login` / `register` / `profile` | AuthController | — |
|
||||
| `membership.index` / `membership.mine` | 会员插件 | `$plans / $subscriptions` |
|
||||
| `membership.paywall` / `membership.paid-teaser` | 会员插件(付费墙) | `$post` |
|
||||
| `payments.sandbox` / `payments.result` | 支付插件 | `$payment` |
|
||||
|
||||
## 付费墙(paywall)覆盖
|
||||
|
||||
@@ -115,25 +126,26 @@ themes/{name}/
|
||||
|
||||
主题视图内置 10 个注入点(Blade `@stack`),后台「主题注入」页管理:
|
||||
|
||||
| 注入点 | 位置 | 典型用途 |
|
||||
|--------|------|----------|
|
||||
| `theme:head` | `</head>` 前 | 统计代码、广告、验证 |
|
||||
| `theme:header` | 页头下方 | 顶部横幅/公告 |
|
||||
| `theme:sidebar_top` | 侧边栏顶部 | 首屏广告 |
|
||||
| `theme:sidebar_bottom` | 侧边栏底部 | 广告/临时链接 |
|
||||
| `theme:content_top` | 内容区顶部 | 列表/文章上方横幅 |
|
||||
| `theme:content_bottom` | 内容区底部 | 分页后广告 |
|
||||
| `theme:post_content_top` | 文章正文前 | 正文顶部广告 |
|
||||
| `theme:post_content_bottom` | 文章正文后 | 正文底部广告 |
|
||||
| `theme:footer` | 页脚前 | 版权上方声明 |
|
||||
| `theme:body_end` | `</body>` 前 | 统计代码 |
|
||||
| 注入点 | 位置 | 典型用途 |
|
||||
| --------------------------- | ------------ | -------------------- |
|
||||
| `theme:head` | `</head>` 前 | 统计代码、广告、验证 |
|
||||
| `theme:header` | 页头下方 | 顶部横幅/公告 |
|
||||
| `theme:sidebar_top` | 侧边栏顶部 | 首屏广告 |
|
||||
| `theme:sidebar_bottom` | 侧边栏底部 | 广告/临时链接 |
|
||||
| `theme:content_top` | 内容区顶部 | 列表/文章上方横幅 |
|
||||
| `theme:content_bottom` | 内容区底部 | 分页后广告 |
|
||||
| `theme:post_content_top` | 文章正文前 | 正文顶部广告 |
|
||||
| `theme:post_content_bottom` | 文章正文后 | 正文底部广告 |
|
||||
| `theme:footer` | 页脚前 | 版权上方声明 |
|
||||
| `theme:body_end` | `</body>` 前 | 统计代码 |
|
||||
|
||||
特性:
|
||||
|
||||
- **同一位置可添加多条**注入块(名称 + HTML + 排序 + 启停),按排序渲染
|
||||
- 插件可通过 filter `theme.inject.{point}` 追加
|
||||
- 主题变量(stylevar 复活):后台「主题注入」→「主题变量」Tab,视图用 `{{ theme('var', 'key') }}` 引用任意 HTML
|
||||
|
||||
新主题须在对应 partial/视图放置 `@stack('theme:xxx')` 才能接收注入。
|
||||
新主题须在对应 partial/视图放置 `@include('partials.theme-inject', ['point' => 'xxx'])`(或 `@stack('theme:xxx')`)才能接收注入。主题变量里的 `ad_header` 等会自动打到对应位置,未映射且含 HTML 的变量落在页脚。保存「主题注入」会清前台整页缓存。
|
||||
|
||||
**声明注入点**:`theme.json` 的 `inject_points` 声明主题实现了哪些注入点(缺省视为全部支持),后台主题卡片会展示,切换主题时一目了然。
|
||||
|
||||
|
||||
+21
-4
@@ -444,18 +444,22 @@ a:hover {
|
||||
max-width: 100%;
|
||||
}
|
||||
.pagination-info {
|
||||
color: #888;
|
||||
background: #f5f7fb;
|
||||
border: 1px solid #d5dbe6;
|
||||
border-radius: 6px;
|
||||
color: #556;
|
||||
font-size: 13px;
|
||||
margin-right: 6px;
|
||||
padding: 6px 10px;
|
||||
margin-right: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.pagination-links a,
|
||||
.pagination-links .current,
|
||||
.pagination-links .disabled {
|
||||
padding: 6px 12px;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
background: #fff;
|
||||
}
|
||||
.pagination-links .current {
|
||||
@@ -466,6 +470,19 @@ a:hover {
|
||||
.pagination-links .disabled {
|
||||
color: #bbb;
|
||||
}
|
||||
.theme-inject {
|
||||
margin: 10px 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.theme-inject:empty {
|
||||
display: none;
|
||||
}
|
||||
.theme-inject img,
|
||||
.theme-inject iframe {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.auth-layout {
|
||||
display: flex;
|
||||
|
||||
@@ -366,18 +366,22 @@ a:hover {
|
||||
max-width: 100%;
|
||||
}
|
||||
.pagination-info {
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
margin-right: 6px;
|
||||
padding: 6px 10px;
|
||||
margin-right: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.pagination-links a,
|
||||
.pagination-links .current,
|
||||
.pagination-links .disabled {
|
||||
padding: 6px 14px;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
background: var(--card);
|
||||
color: var(--text);
|
||||
}
|
||||
@@ -389,6 +393,19 @@ a:hover {
|
||||
.pagination-links .disabled {
|
||||
color: var(--muted);
|
||||
}
|
||||
.theme-inject {
|
||||
margin: 12px 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.theme-inject:empty {
|
||||
display: none;
|
||||
}
|
||||
.theme-inject img,
|
||||
.theme-inject iframe {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.m-footer {
|
||||
border-top: 1px solid var(--border);
|
||||
|
||||
@@ -370,34 +370,63 @@ a:hover {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
margin: 12px 0;
|
||||
margin: 14px 0;
|
||||
clear: both;
|
||||
}
|
||||
.pagination-links {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
gap: 1px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
margin: 12px 0;
|
||||
margin: 0;
|
||||
}
|
||||
.pagination-info {
|
||||
color: #888;
|
||||
background: #f5fbff;
|
||||
border: 1px solid #86b9d6;
|
||||
color: #336;
|
||||
font-size: 12px;
|
||||
margin-right: 6px;
|
||||
padding: 2px 6px;
|
||||
margin-right: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.pagination-links a,
|
||||
.pagination-links .current,
|
||||
.pagination-links .disabled {
|
||||
padding: 2px 7px;
|
||||
border: 1px solid #d8dfe6;
|
||||
padding: 2px 6px;
|
||||
border: 1px solid #dedeb8;
|
||||
background: #fff;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
min-width: 1.6em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
.pagination-links a:hover {
|
||||
background: #f5fbff;
|
||||
border-color: #86b9d6;
|
||||
}
|
||||
.pagination-links .current {
|
||||
background: #1c62b0;
|
||||
color: #fff;
|
||||
background: #ffffd9;
|
||||
color: #92a05a;
|
||||
font-weight: 700;
|
||||
border-color: #dedeb8;
|
||||
}
|
||||
.pagination-links .disabled {
|
||||
color: #999;
|
||||
}
|
||||
.theme-inject {
|
||||
margin: 8px 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.theme-inject:empty {
|
||||
display: none;
|
||||
}
|
||||
.theme-inject img,
|
||||
.theme-inject iframe {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#footer {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<div class="container main-layout">
|
||||
<main class="content">
|
||||
<h1 class="list-title">文章归档</h1>
|
||||
@include('partials.theme-inject', ['point' => 'content_top'])
|
||||
|
||||
@forelse($archives as $year => $months)
|
||||
<h2 class="archive-year">{{ $year }} 年</h2>
|
||||
@@ -24,6 +25,7 @@
|
||||
@empty
|
||||
<div class="empty">暂无归档</div>
|
||||
@endforelse
|
||||
@include('partials.theme-inject', ['point' => 'content_bottom'])
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
@endif
|
||||
|
||||
@include('partials.view-mode-switcher')
|
||||
@include('partials.theme-inject', ['point' => 'content_top'])
|
||||
|
||||
@forelse($posts as $post)
|
||||
@include('partials.post-card', ['post' => $post])
|
||||
@@ -20,6 +21,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
@include('partials.theme-inject', ['point' => 'content_bottom'])
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
|
||||
@include('partials.view-mode-switcher')
|
||||
@include('partials.theme-inject', ['point' => 'content_top'])
|
||||
|
||||
@forelse($posts as $post)
|
||||
@include('partials.post-card', ['post' => $post])
|
||||
@@ -33,6 +34,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
@include('partials.theme-inject', ['point' => 'content_bottom'])
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@stack('theme:footer')
|
||||
@include('partials.theme-inject', ['point' => 'footer'])
|
||||
<footer class="site-footer">
|
||||
<div class="container">
|
||||
<p>
|
||||
|
||||
@@ -29,4 +29,4 @@
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
@stack('theme:header')
|
||||
@include('partials.theme-inject', ['point' => 'header'])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
@if ($paginator->hasPages())
|
||||
<nav class="pagination-links" role="navigation" aria-label="分页">
|
||||
<span class="pagination-info">第 {{ $paginator->currentPage() }} / {{ $paginator->lastPage() }} 页</span>
|
||||
<span class="pagination-info">{{ $paginator->currentPage() }} / {{ $paginator->lastPage() }}</span>
|
||||
|
||||
@if ($paginator->onFirstPage())
|
||||
<span class="disabled">«</span>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<aside class="sidebar">
|
||||
@stack('theme:sidebar_top')
|
||||
@include('partials.theme-inject', ['point' => 'sidebar_top'])
|
||||
<section class="widget">
|
||||
<h3 class="widget-title">分类</h3>
|
||||
<ul class="widget-list">
|
||||
@@ -84,5 +84,5 @@
|
||||
<li>标签:{{ $blogStats['tags'] }} 个</li>
|
||||
</ul>
|
||||
</section>
|
||||
@stack('theme:sidebar_bottom')
|
||||
|
||||
@include('partials.theme-inject', ['point' => 'sidebar_bottom'])
|
||||
</aside>
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
@php
|
||||
$injected = trim($__env->yieldPushContent('theme:'.$point));
|
||||
@endphp
|
||||
@if($injected !== '')
|
||||
<div class="theme-inject theme-inject-{{ $point }}">{!! $injected !!}</div>
|
||||
@endif
|
||||
@@ -11,6 +11,7 @@
|
||||
</form>
|
||||
|
||||
@include('partials.view-mode-switcher')
|
||||
@include('partials.theme-inject', ['point' => 'content_top'])
|
||||
|
||||
@forelse($posts as $post)
|
||||
@include('partials.post-card', ['post' => $post])
|
||||
@@ -19,6 +20,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
@include('partials.theme-inject', ['point' => 'content_bottom'])
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>
|
||||
|
||||
@@ -50,10 +50,11 @@
|
||||
<span>· 阅读 {{ $post->views }}</span>
|
||||
</div>
|
||||
|
||||
@stack('theme:post_content_top')
|
||||
@include('partials.theme-inject', ['point' => 'post_content_top'])
|
||||
<div class="post-content">
|
||||
{!! $contentHtml !!}
|
||||
</div>
|
||||
@include('partials.theme-inject', ['point' => 'post_content_bottom'])
|
||||
|
||||
@if($post->tags->isNotEmpty())
|
||||
<div class="post-tags">
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<h1 class="list-title">标签:{{ $tag->name }}</h1>
|
||||
|
||||
@include('partials.view-mode-switcher')
|
||||
@include('partials.theme-inject', ['point' => 'content_top'])
|
||||
|
||||
@forelse($posts as $post)
|
||||
@include('partials.post-card', ['post' => $post])
|
||||
@@ -15,6 +16,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
@include('partials.theme-inject', ['point' => 'content_bottom'])
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>
|
||||
|
||||
@@ -72,7 +72,7 @@ class HomeViewModeTest extends TestCase
|
||||
|
||||
$this->get('/')
|
||||
->assertOk()
|
||||
->assertSee('第 1 /', false)
|
||||
->assertSee('页', false);
|
||||
->assertSee('pagination-info', false)
|
||||
->assertSee('1 /', false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ class SablogImportTest extends TestCase
|
||||
$pdo->exec('CREATE TABLE sablog_comments (commentid INTEGER PRIMARY KEY, articleid INTEGER, author TEXT, url TEXT, dateline INTEGER, content TEXT, ipaddress TEXT, visible INTEGER)');
|
||||
$pdo->exec('CREATE TABLE sablog_links (linkid INTEGER PRIMARY KEY, displayorder INTEGER, name TEXT, url TEXT, note TEXT, visible INTEGER)');
|
||||
$pdo->exec('CREATE TABLE sablog_tags (tagid INTEGER PRIMARY KEY, tag TEXT, usenum INTEGER, aids TEXT)');
|
||||
$pdo->exec('CREATE TABLE sablog_stylevars (stylevarid INTEGER PRIMARY KEY, title TEXT, value TEXT, description TEXT)');
|
||||
$pdo->exec('CREATE TABLE sablog_settings (title TEXT PRIMARY KEY, value TEXT)');
|
||||
$pdo->exec('CREATE TABLE sablog_users (userid INTEGER PRIMARY KEY, username TEXT, password TEXT, logincount INTEGER, loginip TEXT, logintime INTEGER, url TEXT, articles INTEGER, regdateline INTEGER, regip TEXT, groupid INTEGER, lastpost INTEGER)');
|
||||
$pdo->exec('CREATE TABLE sablog_attachments (attachmentid INTEGER PRIMARY KEY, articleid INTEGER, dateline INTEGER, filename TEXT, filetype TEXT, filesize INTEGER, downloads INTEGER, filepath TEXT, thumb_filepath TEXT, thumb_width INTEGER, thumb_height INTEGER, isimage INTEGER)');
|
||||
@@ -69,6 +70,7 @@ class SablogImportTest extends TestCase
|
||||
$pdo->exec("INSERT INTO sablog_links VALUES (1, 0, '友链A', 'https://a.example.com', '', 1)");
|
||||
$pdo->exec("INSERT INTO sablog_tags VALUES (1, 'laravel', 1, '10'), (2, '随笔', 1, '10')");
|
||||
$pdo->exec("INSERT INTO sablog_settings VALUES ('name', '老站名'), ('description', '老描述'), ('templatename', 'default')");
|
||||
$pdo->exec("INSERT INTO sablog_stylevars VALUES (1, 'ad_header', '<div class=\"legacy-ad\">老广告</div>', '')");
|
||||
$pdo->exec("INSERT INTO sablog_attachments VALUES (1, 10, $now, 'photo.jpg', 'image/jpeg', 100, 3, '2020/09/photo.jpg', '', 0, 0, 1), (2, 10, $now, 'archive.zip', 'application/zip', 200, 1, '2020/09/archive.zip', '', 0, 0, 0)");
|
||||
}
|
||||
|
||||
@@ -116,6 +118,7 @@ class SablogImportTest extends TestCase
|
||||
// 设置映射
|
||||
$this->assertSame('老站名', Setting::get('site_name'));
|
||||
$this->assertSame('sablog', Setting::get('active_theme'));
|
||||
$this->assertSame('<div class="legacy-ad">老广告</div>', theme('var', 'ad_header', ''));
|
||||
}
|
||||
|
||||
public function test_import_converts_content_to_markdown(): void
|
||||
|
||||
@@ -57,7 +57,7 @@ class ThemeInjectTest extends TestCase
|
||||
['point' => 'footer', 'title' => '第二条', 'html' => '<div id="inject-2">second</div>', 'sort' => 2, 'enabled' => true],
|
||||
]);
|
||||
|
||||
$html = $this->get('/posts/inject-test.shtml')->getContent();
|
||||
$html = $this->get('/show-'.Post::where('slug', 'inject-test')->value('id').'.shtml')->getContent();
|
||||
|
||||
$pos1 = strpos($html, 'id="inject-1"');
|
||||
$pos2 = strpos($html, 'id="inject-2"');
|
||||
@@ -82,7 +82,7 @@ class ThemeInjectTest extends TestCase
|
||||
['point' => 'post_content_bottom', 'title' => '正文后广告', 'html' => '<div id="post-bottom-ad">BOTTOM</div>', 'sort' => 1, 'enabled' => true],
|
||||
]);
|
||||
|
||||
$html = $this->get('/posts/inject-test.shtml')->getContent();
|
||||
$html = $this->get('/show-'.Post::where('slug', 'inject-test')->value('id').'.shtml')->getContent();
|
||||
|
||||
$this->assertStringContainsString('post-top-ad', $html);
|
||||
$this->assertStringContainsString('post-bottom-ad', $html);
|
||||
@@ -97,4 +97,21 @@ class ThemeInjectTest extends TestCase
|
||||
// theme('var') 直接可用
|
||||
$this->assertSame('<div class="header-ad">头部广告</div>', theme('var', 'ad_header', ''));
|
||||
}
|
||||
|
||||
public function test_content_top_and_stylevars_render_on_home(): void
|
||||
{
|
||||
Setting::set('inject.blocks', [
|
||||
['point' => 'content_top', 'title' => '首页广告', 'html' => '<div id="home-top-ad">首页广告位</div>', 'sort' => 1, 'enabled' => true],
|
||||
]);
|
||||
Setting::set('theme_vars_sablog', [
|
||||
'ad_header' => '<div class="header-ad">头部广告</div>',
|
||||
'huangjinlian' => '<div class="footer-ad">页脚广告</div>',
|
||||
]);
|
||||
|
||||
$this->get('/')
|
||||
->assertOk()
|
||||
->assertSee('首页广告位', false)
|
||||
->assertSee('头部广告', false)
|
||||
->assertSee('页脚广告', false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<p>由 LaraLog 驱动 · Demo 主题</p>
|
||||
</div>
|
||||
</footer>
|
||||
@stack('theme:footer')
|
||||
@include('partials.theme-inject', ['point' => 'footer'])
|
||||
@stack('theme:body_end')
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -23,4 +23,4 @@
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
@stack('theme:header')
|
||||
@include('partials.theme-inject', ['point' => 'header'])
|
||||
|
||||
@@ -366,18 +366,22 @@ a:hover {
|
||||
max-width: 100%;
|
||||
}
|
||||
.pagination-info {
|
||||
background: var(--bg);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
margin-right: 6px;
|
||||
padding: 6px 10px;
|
||||
margin-right: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.pagination-links a,
|
||||
.pagination-links .current,
|
||||
.pagination-links .disabled {
|
||||
padding: 6px 14px;
|
||||
padding: 6px 10px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
background: var(--card);
|
||||
color: var(--text);
|
||||
}
|
||||
@@ -389,6 +393,19 @@ a:hover {
|
||||
.pagination-links .disabled {
|
||||
color: var(--muted);
|
||||
}
|
||||
.theme-inject {
|
||||
margin: 12px 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.theme-inject:empty {
|
||||
display: none;
|
||||
}
|
||||
.theme-inject img,
|
||||
.theme-inject iframe {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.m-footer {
|
||||
border-top: 1px solid var(--border);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@stack('theme:footer')
|
||||
@include('partials.theme-inject', ['point' => 'footer'])
|
||||
<footer class="m-footer">
|
||||
<div class="m-container">
|
||||
<p>© {{ date('Y') }} {{ $siteName }}
|
||||
|
||||
@@ -23,4 +23,4 @@
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
@stack('theme:header')
|
||||
@include('partials.theme-inject', ['point' => 'header'])
|
||||
|
||||
@@ -370,34 +370,63 @@ a:hover {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
margin: 12px 0;
|
||||
margin: 14px 0;
|
||||
clear: both;
|
||||
}
|
||||
.pagination-links {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
gap: 1px;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
max-width: 100%;
|
||||
margin: 12px 0;
|
||||
margin: 0;
|
||||
}
|
||||
.pagination-info {
|
||||
color: #888;
|
||||
background: #f5fbff;
|
||||
border: 1px solid #86b9d6;
|
||||
color: #336;
|
||||
font-size: 12px;
|
||||
margin-right: 6px;
|
||||
padding: 2px 6px;
|
||||
margin-right: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.pagination-links a,
|
||||
.pagination-links .current,
|
||||
.pagination-links .disabled {
|
||||
padding: 2px 7px;
|
||||
border: 1px solid #d8dfe6;
|
||||
padding: 2px 6px;
|
||||
border: 1px solid #dedeb8;
|
||||
background: #fff;
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
min-width: 1.6em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
}
|
||||
.pagination-links a:hover {
|
||||
background: #f5fbff;
|
||||
border-color: #86b9d6;
|
||||
}
|
||||
.pagination-links .current {
|
||||
background: #1c62b0;
|
||||
color: #fff;
|
||||
background: #ffffd9;
|
||||
color: #92a05a;
|
||||
font-weight: 700;
|
||||
border-color: #dedeb8;
|
||||
}
|
||||
.pagination-links .disabled {
|
||||
color: #999;
|
||||
}
|
||||
.theme-inject {
|
||||
margin: 8px 0;
|
||||
max-width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.theme-inject:empty {
|
||||
display: none;
|
||||
}
|
||||
.theme-inject img,
|
||||
.theme-inject iframe {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#footer {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
@endif
|
||||
|
||||
@include('partials.view-mode-switcher')
|
||||
@include('partials.theme-inject', ['point' => 'content_top'])
|
||||
|
||||
@forelse($posts as $post)
|
||||
@include('partials.post-card', ['post' => $post])
|
||||
@@ -20,6 +21,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
@include('partials.theme-inject', ['point' => 'content_bottom'])
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>{{-- #page --}}
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
|
||||
@include('partials.view-mode-switcher')
|
||||
@include('partials.theme-inject', ['point' => 'content_top'])
|
||||
|
||||
@forelse($posts as $post)
|
||||
@include('partials.post-card', ['post' => $post])
|
||||
@@ -33,6 +34,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
@include('partials.theme-inject', ['point' => 'content_bottom'])
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>{{-- #page --}}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@stack('theme:footer')
|
||||
@include('partials.theme-inject', ['point' => 'footer'])
|
||||
<footer id="footer">
|
||||
<p>© {{ date('Y') }} {{ $siteName }}
|
||||
@if($siteIcp)<a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">{{ $siteIcp }}</a>@endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<a href="{{ route('home') }}">{{ $siteName }}</a>
|
||||
<p class="description">{{ $siteDescription }}</p>
|
||||
</div>
|
||||
@stack('theme:header')
|
||||
@include('partials.theme-inject', ['point' => 'header'])
|
||||
<nav id="nav">
|
||||
<ul>
|
||||
<li class="{{ request()->routeIs('home') ? 'current_page_item' : '' }}"><a href="{{ route('home') }}">首页</a></li>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<aside class="sidebar">
|
||||
@stack('theme:sidebar_top')
|
||||
@include('partials.theme-inject', ['point' => 'sidebar_top'])
|
||||
<div class="searchbox">
|
||||
<form action="{{ route('search') }}" method="get">
|
||||
<input type="search" name="q" value="{{ request('q', request('keyword', '')) }}" placeholder="搜索文章">
|
||||
@@ -83,5 +83,5 @@
|
||||
<li>标签 {{ $blogStats['tags'] }} 个</li>
|
||||
</ul>
|
||||
</section>
|
||||
@stack('theme:sidebar_bottom')
|
||||
@include('partials.theme-inject', ['point' => 'sidebar_bottom'])
|
||||
</aside>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
</form>
|
||||
|
||||
@include('partials.view-mode-switcher')
|
||||
@include('partials.theme-inject', ['point' => 'content_top'])
|
||||
|
||||
@forelse($posts as $post)
|
||||
@include('partials.post-card', ['post' => $post])
|
||||
@@ -19,6 +20,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
@include('partials.theme-inject', ['point' => 'content_bottom'])
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>{{-- #page --}}
|
||||
|
||||
@@ -48,11 +48,11 @@
|
||||
<span>· 阅读 {{ $post->views }}</span>
|
||||
</div>
|
||||
|
||||
@stack('theme:post_content_top')
|
||||
@include('partials.theme-inject', ['point' => 'post_content_top'])
|
||||
<div class="post-content">
|
||||
{!! $contentHtml !!}
|
||||
</div>
|
||||
@stack('theme:post_content_bottom')
|
||||
@include('partials.theme-inject', ['point' => 'post_content_bottom'])
|
||||
|
||||
@if($post->tags->isNotEmpty())
|
||||
<div class="post-tags">
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<h1 class="list-title">标签:{{ $tag->name }}</h1>
|
||||
|
||||
@include('partials.view-mode-switcher')
|
||||
@include('partials.theme-inject', ['point' => 'content_top'])
|
||||
|
||||
@forelse($posts as $post)
|
||||
@include('partials.post-card', ['post' => $post])
|
||||
@@ -15,6 +16,7 @@
|
||||
@endforelse
|
||||
|
||||
@include('partials.pagination', ['paginator' => $posts])
|
||||
@include('partials.theme-inject', ['point' => 'content_bottom'])
|
||||
</main>
|
||||
@include('partials.sidebar')
|
||||
</div>{{-- #page --}}
|
||||
|
||||
Reference in New Issue
Block a user