From 2aa60f87edc5350c76290c9b69e3ce2f4015b91e Mon Sep 17 00:00:00 2001 From: augushong Date: Sat, 2 May 2026 09:06:47 +0800 Subject: [PATCH] feat(phone-image): add cover_text migration and rewrite CSS to xiaohongshu classic style T1: Add cover_text text field to post table for phone image layout cover text T2: Rewrite phone-image-templates.css - remove tpl-magazine/tpl-mixed, merge tpl-minimal into base styles, add content-flow/break-inserter/page-break-marker/page-alignment-toggle styles --- .../20260502000000_add_cover_text_to_post.php | 14 + public/static/css/phone-image-templates.css | 580 +++++------------- 2 files changed, 171 insertions(+), 423 deletions(-) create mode 100644 database/migrations/20260502000000_add_cover_text_to_post.php diff --git a/database/migrations/20260502000000_add_cover_text_to_post.php b/database/migrations/20260502000000_add_cover_text_to_post.php new file mode 100644 index 0000000..7e21b37 --- /dev/null +++ b/database/migrations/20260502000000_add_cover_text_to_post.php @@ -0,0 +1,14 @@ +table('post'); + $table->addColumn(Column::make('cover_text', 'text')->setComment('封面文案,用于手机图片排版封面展示')->setNull(true)) + ->update(); + } +} diff --git a/public/static/css/phone-image-templates.css b/public/static/css/phone-image-templates.css index 18902c8..8c4e55d 100644 --- a/public/static/css/phone-image-templates.css +++ b/public/static/css/phone-image-templates.css @@ -9,11 +9,11 @@ CSS grid, object-fit, position:sticky, CSS animations ============================================ */ -/* --- CSS Custom Properties --- */ +/* --- CSS Custom Properties (小红书经典风格) --- */ :root { /* 字号 */ --pi-font-size-base: 14px; - --pi-font-size-title: 24px; + --pi-font-size-title: 26px; --pi-font-size-subtitle: 16px; --pi-font-size-small: 12px; /* 行高 */ @@ -22,6 +22,7 @@ --pi-spacing: 20px; --pi-spacing-sm: 10px; --pi-spacing-lg: 30px; + --pi-spacing-xs: 5px; /* 颜色 */ --pi-color-text: #333333; --pi-color-text-light: #666666; @@ -29,6 +30,8 @@ --pi-color-bg: #ffffff; --pi-color-accent: #1890ff; --pi-color-border: #eeeeee; + /* 圆角 */ + --pi-radius: 12px; /* 字体 */ --pi-font-family: 'Source Han Sans', 'SourceHanSans-Normal', sans-serif; } @@ -91,9 +94,10 @@ } .page-cover .cover-title { - font-size: 32px; - font-weight: bold; - line-height: 1.4; + font-size: 28px; + font-weight: normal; + letter-spacing: 2px; + line-height: 1.5; margin-bottom: var(--pi-spacing); color: var(--pi-color-text); word-break: break-word; @@ -199,16 +203,17 @@ /* 内容页 - 页头区域 */ .page-header { - padding-bottom: var(--pi-spacing-sm); - margin-bottom: var(--pi-spacing); - border-bottom: 1px solid var(--pi-color-border); + border-bottom: none; + padding-bottom: 0; + margin-bottom: 20px; } .page-header .page-title { - font-size: var(--pi-font-size-title); - font-weight: bold; + font-size: 20px; + font-weight: normal; + letter-spacing: 1px; + color: #666; line-height: 1.4; - color: var(--pi-color-text); word-break: break-word; } @@ -223,25 +228,30 @@ flex: 1; overflow: hidden; word-break: break-word; + line-height: 2.0; } .page-content p { - margin-bottom: var(--pi-spacing-sm); text-indent: 2em; + margin-bottom: 16px; + color: #333; } .page-content h2 { - font-size: 20px; - font-weight: bold; - margin-top: var(--pi-spacing); - margin-bottom: var(--pi-spacing-sm); + font-weight: normal; + font-size: 18px; + letter-spacing: 1px; + margin-top: 24px; + margin-bottom: 12px; + color: #333; } .page-content h3 { - font-size: var(--pi-font-size-subtitle); - font-weight: bold; - margin-top: var(--pi-spacing-sm); - margin-bottom: var(--pi-spacing-sm); + font-weight: normal; + font-size: 16px; + margin-top: 20px; + margin-bottom: 10px; + color: #555; } .page-content h4 { @@ -267,11 +277,11 @@ } .page-content blockquote { - border-left: 3px solid var(--pi-color-accent); - padding-left: var(--pi-spacing-sm); + border-left: 1px solid #ccc; + font-style: normal; + color: #888; + padding-left: 15px; margin: var(--pi-spacing-sm) 0; - color: var(--pi-color-text-light); - font-style: italic; } .page-content ul, @@ -286,11 +296,11 @@ /* 内容页 - 页脚区域 */ .page-footer { - padding-top: var(--pi-spacing-sm); + border-top: none; + padding-top: 0; margin-top: var(--pi-spacing-sm); - border-top: 1px solid var(--pi-color-border); - font-size: var(--pi-font-size-small); - color: var(--pi-color-text-lighter); + font-size: 11px; + color: #bbb; display: flex; justify-content: space-between; align-items: center; @@ -307,15 +317,17 @@ } .page-summary .summary-title { - font-size: var(--pi-font-size-title); - font-weight: bold; + font-weight: normal; + letter-spacing: 2px; + font-size: 22px; margin-bottom: var(--pi-spacing); color: var(--pi-color-text); } .page-summary .summary-text { font-size: var(--pi-font-size-subtitle); - color: var(--pi-color-text-light); + color: #aaa; + font-weight: normal; margin-bottom: var(--pi-spacing); line-height: 1.6; } @@ -326,25 +338,16 @@ .page-summary .summary-footer { font-size: var(--pi-font-size-small); - color: var(--pi-color-text-lighter); + color: #ccc; } /* ============================================ Font Variants - 三种可选字体 ============================================ */ .font-source-han-sans { --pi-font-family: 'Source Han Sans', 'SourceHanSans-Normal', sans-serif; } -.font-alibaba-puhuiti { - --pi-font-family: 'AlibabaPuHuiTi', sans-serif; -} - -.font-lxgw-wenkai { - --pi-font-family: 'LXGWWenKai', cursive; -} - /* ============================================ Article Images 文章内图片样式 @@ -367,10 +370,10 @@ } /* ============================================ - Page Number + Page Number Indicator 页码指示器 ============================================ */ -.page-number { +.page-number-indicator { position: absolute; bottom: 10px; right: 15px; @@ -379,412 +382,143 @@ } /* ============================================ - Template Namespaces - 三个模板命名空间, 基础结构样式 - 后续Task 8-10会填充详细样式 + Vertical Alignment (逐页对齐) ============================================ */ - -/* --- 简约文字卡片模板 --- */ -.tpl-minimal { - /* 基础结构: 白底黑字, 大量留白, 现代简约风格 */ +.page-body.valign-center .page-content { + display: flex; + flex-direction: column; + justify-content: center; } -/* 封面页 - 居中大标题 + 副标题 + 日期 */ -.tpl-minimal .page-cover .cover-title { - font-size: 28px; - font-weight: normal; - letter-spacing: 2px; - line-height: 1.5; -} - -.tpl-minimal .page-cover .cover-subtitle { - font-weight: normal; - letter-spacing: 1px; - color: #999; -} - -.tpl-minimal .page-cover .cover-meta { - letter-spacing: 1px; -} - -/* 内容页 - 页头区域 */ -.tpl-minimal .page-header { - border-bottom: none; - padding-bottom: 0; - margin-bottom: 20px; -} - -.tpl-minimal .page-header .page-title { - font-size: 20px; - font-weight: normal; - letter-spacing: 1px; - color: #666; -} - -/* 内容页 - 正文区域: 宽行高(2.0), 大段落间距, 首行缩进2em */ -.tpl-minimal .page-content { - line-height: 2.0; -} - -.tpl-minimal .page-content p { - text-indent: 2em; - margin-bottom: 16px; - color: #333; -} - -.tpl-minimal .page-content h2 { - font-weight: normal; - font-size: 18px; - letter-spacing: 1px; - margin-top: 24px; - margin-bottom: 12px; - color: #333; -} - -.tpl-minimal .page-content h3 { - font-weight: normal; - font-size: 16px; - margin-top: 20px; - margin-bottom: 10px; - color: #555; -} - -.tpl-minimal .page-content blockquote { - border-left: 1px solid #ccc; - font-style: normal; - color: #888; - padding-left: 15px; -} - -.tpl-minimal .page-content .article-image { - border-radius: 4px; -} - -.tpl-minimal .page-content .article-image-full { - border-radius: 0; -} - -/* 内容页 - 页脚区域: 小号版权 + 页码, 细线分隔 */ -.tpl-minimal .page-footer { - border-top: none; - padding-top: 0; - font-size: 11px; - color: #bbb; -} - -/* 总结页/尾页 */ -.tpl-minimal .page-summary .summary-title { - font-weight: normal; - letter-spacing: 2px; - font-size: 22px; -} - -.tpl-minimal .page-summary .summary-text { - color: #aaa; - font-weight: normal; -} - -.tpl-minimal .page-summary .summary-footer { - color: #ccc; -} - -/* --- 杂志模板 - 完整样式 --- */ -.tpl-magazine .page-cover { - padding: 0; - justify-content: flex-end; - padding-bottom: 40px; - position: relative; -} - -.tpl-magazine .page-cover::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - right: 0; - height: 4px; - background: #1890ff; -} - -.tpl-magazine .page-cover .cover-title { - font-size: 26px; - font-weight: bold; - line-height: 1.4; - letter-spacing: 1px; - position: relative; - padding-bottom: 15px; -} - -.tpl-magazine .page-cover .cover-subtitle { - font-weight: normal; - color: #666; - letter-spacing: 0.5px; -} - -.tpl-magazine .page-cover .cover-meta { - position: relative; - padding: 8px 12px; - background: #f5f5f5; - border-radius: 2px; -} - -.tpl-magazine .page-header { - border-bottom: 2px solid #1890ff; - padding-bottom: 10px; - margin-bottom: 15px; -} - -.tpl-magazine .page-header .page-title { - font-size: 22px; - font-weight: bold; - letter-spacing: 0.5px; -} - -.tpl-magazine .page-content { - line-height: 1.8; -} - -.tpl-magazine .page-content p { - margin-bottom: 14px; - text-indent: 2em; - color: #333; -} - -.tpl-magazine .page-content p:first-child { - text-indent: 0; -} - -.tpl-magazine .page-content p:first-child::first-letter { - font-size: 3.2em; - font-weight: bold; - float: left; - line-height: 1; - margin-right: 8px; - margin-top: 4px; - color: #1890ff; -} - -.tpl-magazine .page-content h2 { - font-size: 20px; - font-weight: bold; - margin-top: 22px; - margin-bottom: 10px; - padding-left: 10px; - border-left: 3px solid #1890ff; -} - -.tpl-magazine .page-content h3 { - font-size: 17px; - font-weight: bold; - margin-top: 16px; - margin-bottom: 8px; - color: #1890ff; -} - -.tpl-magazine .page-content blockquote { - border-left: 4px solid #1890ff; - background: #f8f9fa; - padding: 12px 15px; - margin: 12px 0; - font-style: normal; - color: #555; - border-radius: 0 4px 4px 0; -} - -.tpl-magazine .page-content .article-image { - border-radius: 2px; -} - -.tpl-magazine .page-footer { - border-top: 2px solid #1890ff; - padding-top: 8px; - color: #1890ff; - font-weight: bold; -} - -.tpl-magazine .page-summary { - background: #f8f9fa; -} - -.tpl-magazine .page-summary .summary-title { - color: #1890ff; - font-size: 24px; - font-weight: bold; -} - -.tpl-magazine .page-summary .summary-text { - color: #666; -} - -.tpl-magazine .page-summary .summary-footer { - border-top: 1px solid #ddd; - padding-top: 15px; - color: #999; -} - -/* --- 图文混排模板 - 完整样式 --- */ -.tpl-mixed { - /* 基础结构: 图文混排 */ -} - -/* 封面页: 图片背景 + 底部文字叠加 */ -.tpl-mixed .page-cover { - justify-content: flex-end; - padding: 0; - padding-bottom: 30px; - position: relative; -} - -.tpl-mixed .page-cover .cover-image { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; -} - -.tpl-mixed .page-cover .cover-title { - position: relative; - z-index: 2; - font-size: 24px; - font-weight: bold; - line-height: 1.4; - color: #fff; - background: rgba(0, 0, 0, 0.5); - padding: 15px 20px; - width: 100%; +/* ============================================ + Content Flow (中间栏内容流) + 所有元素按实际尺寸纵向排列 + ============================================ */ +.content-flow { + width: 540px; + padding: 20px; box-sizing: border-box; - text-align: left; + background: #fff; + min-height: 100%; } -.tpl-mixed .page-cover .cover-subtitle { +.content-flow-block { position: relative; - z-index: 2; - color: #eee; - background: rgba(0, 0, 0, 0.3); - padding: 8px 20px; - width: 100%; - box-sizing: border-box; - text-align: left; margin-bottom: 0; } -.tpl-mixed .page-cover .cover-meta { - position: relative; - z-index: 2; - color: #ccc; - padding: 5px 20px; - background: rgba(0, 0, 0, 0.3); - width: 100%; - box-sizing: border-box; - text-align: left; +.content-flow-block img { + max-width: 100%; + height: auto; + display: block; } -/* 无封面图时的降级样式 */ -.tpl-mixed .page-cover.no-cover-image { +/* --- 分页插入区域 --- */ +.break-inserter { + height: 20px; + border-top: 1px dashed #ddd; + display: flex; + align-items: center; justify-content: center; - background: #333; + margin: 2px 0; + cursor: pointer; } -.tpl-mixed .page-cover.no-cover-image .cover-title { +.break-inserter:hover { + border-color: var(--pi-color-accent); + background: rgba(24, 144, 255, 0.05); +} + +.break-inserter-btn { + opacity: 0; + width: 20px; + height: 20px; + border-radius: 50%; + background: var(--pi-color-accent); + color: #fff; + font-size: 14px; + line-height: 20px; text-align: center; - background: none; - font-size: 26px; + border: none; + cursor: pointer; + padding: 0; } -.tpl-mixed .page-cover.no-cover-image .cover-subtitle { +.break-inserter:hover .break-inserter-btn { + opacity: 1; +} + +/* --- 已插入的分页标记 --- */ +.page-break-marker { + height: 30px; + background: #fff3f3; + border: 1px dashed #ff4d4f; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + margin: 4px 0; + position: relative; +} + +.page-break-marker .break-marker-label { + font-size: 12px; + color: #ff4d4f; + user-select: none; +} + +.page-break-marker .remove-break-btn { + position: absolute; + right: 8px; + top: 50%; + margin-top: -10px; + width: 20px; + height: 20px; + border-radius: 50%; + background: #ff4d4f; + color: #fff; + font-size: 14px; + line-height: 20px; text-align: center; - background: none; + border: none; + cursor: pointer; + padding: 0; + opacity: 0; } -.tpl-mixed .page-cover.no-cover-image .cover-meta { - text-align: center; - background: none; +.page-break-marker:hover .remove-break-btn { + opacity: 1; } -/* 内容页头部 */ -.tpl-mixed .page-header { - border-bottom: 2px solid #333; - padding-bottom: 8px; -} - -.tpl-mixed .page-header .page-title { - font-size: 20px; - font-weight: bold; -} - -/* 内容页正文 */ -.tpl-mixed .page-content { - line-height: 1.8; -} - -.tpl-mixed .page-content p { - margin-bottom: 12px; - text-indent: 2em; - color: #333; -} - -.tpl-mixed .page-content h2 { - font-size: 19px; - font-weight: bold; - margin-top: 18px; - margin-bottom: 8px; - padding: 6px 12px; - background: #f0f0f0; - border-left: 4px solid #333; -} - -.tpl-mixed .page-content h3 { - font-size: 16px; - font-weight: bold; - margin-top: 14px; - margin-bottom: 6px; - color: #555; -} - -.tpl-mixed .page-content blockquote { - border-left: 3px solid #333; - background: #f8f8f8; - padding: 10px 15px; - font-style: normal; +/* --- 逐页对齐切换指示器 --- */ +.page-alignment-toggle { + position: absolute; + top: 8px; + right: 8px; + z-index: 10; + opacity: 0.5; + cursor: pointer; + width: 24px; + height: 24px; + border-radius: 4px; + background: rgba(0, 0, 0, 0.06); + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; color: #666; + user-select: none; + border: none; + padding: 0; } -.tpl-mixed .page-content .article-image { - border-radius: 0; - margin: 15px 0; +.page-alignment-toggle:hover { + opacity: 1; + background: rgba(0, 0, 0, 0.1); } -.tpl-mixed .page-content .article-image-full { - margin: 0 -20px; - max-width: none; - width: 540px; -} - -/* 内容页底部 */ -.tpl-mixed .page-footer { - border-top: 1px solid #333; - color: #333; - font-weight: bold; -} - -/* 总结页 */ -.tpl-mixed .page-summary { - background: #f5f5f5; -} - -.tpl-mixed .page-summary .summary-title { - font-size: 28px; - font-weight: bold; - color: #333; -} - -.tpl-mixed .page-summary .summary-text { - color: #666; -} - -.tpl-mixed .page-summary .summary-footer { - color: #999; - border-top: 1px solid #ddd; - padding-top: 15px; +.page-alignment-toggle.active-center { + opacity: 1; + background: rgba(24, 144, 255, 0.15); + color: var(--pi-color-accent); }