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
This commit is contained in:
augushong
2026-05-02 09:06:47 +08:00
parent 0e3a442ddd
commit 2aa60f87ed
2 changed files with 171 additions and 423 deletions

View File

@@ -0,0 +1,14 @@
<?php
use think\migration\Migrator;
use think\migration\db\Column;
class AddCoverTextToPost extends Migrator
{
public function change()
{
$table = $this->table('post');
$table->addColumn(Column::make('cover_text', 'text')->setComment('封面文案,用于手机图片排版封面展示')->setNull(true))
->update();
}
}

View File

@@ -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);
}