feat(content): 小程序卡片按 card_mode(大/小图) + 图标标准化(去emoji)
- 卡片显示由 card_mode 决定(big 大图 / 其余 小图),图片 object-fit cover + 固定比例(大16:9/缩略方) 裁切 - app.scss 加通用线性图标 CSS mask(.ic-play/heart/check/thumb/share/cmt,lucide 风格) - 详情页/卡片 emoji(👍↗♥✎✓▶😊🖼) 全部换为标准 mask 图标 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -343,3 +343,16 @@ page { -ms-overflow-style: none; scrollbar-width: none; }
|
||||
color: #ffd28a;
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
/* 通用线性图标(CSS mask SVG,仿 lucide;禁用 emoji 图标) */
|
||||
.ic {
|
||||
display: inline-block; width: 36rpx; height: 36rpx; background-color: currentColor;
|
||||
-webkit-mask-repeat: no-repeat; -webkit-mask-position: center; -webkit-mask-size: contain;
|
||||
mask-repeat: no-repeat; mask-position: center; mask-size: contain;
|
||||
}
|
||||
.ic-play { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23fff'%3E%3Cpath d='M5 3l14 9-14 9V3z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23fff'%3E%3Cpath d='M5 3l14 9-14 9V3z'/%3E%3C/svg%3E"); }
|
||||
.ic-heart { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2'%3E%3Cpath d='M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.6l-1-1a5.5 5.5 0 0 0-7.8 7.8l1 1L12 21l7.8-7.6 1-1a5.5 5.5 0 0 0 0-7.8z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2'%3E%3Cpath d='M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.6l-1-1a5.5 5.5 0 0 0-7.8 7.8l1 1L12 21l7.8-7.6 1-1a5.5 5.5 0 0 0 0-7.8z'/%3E%3C/svg%3E"); }
|
||||
.ic-check { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2.5'%3E%3Cpath d='M20 6L9 17l-5-5'/%3E%3C/svg%3E"); }
|
||||
.ic-thumb { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2'%3E%3Cpath d='M7 10v12M15 5.9s0-1-.5-2a1.5 1.5 0 0 0-2.8 1C12.4 6.6 11 10 11 10h6a2 2 0 0 1 2 2.5l-1.4 5.6a2 2 0 0 1-2 1.5H7M15 6l2-1.5a1.5 1.5 0 0 1 2.7 1.3L18 13M7 22H4a2 2 0 0 1-2-2V12a2 2 0 0 1 2-2h3'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2'%3E%3Cpath d='M7 10v12M15 5.9s0-1-.5-2a1.5 1.5 0 0 0-2.8 1C12.4 6.6 11 10 11 10h6a2 2 0 0 1 2 2.5l-1.4 5.6a2 2 0 0 1-2 1.5H7M15 6l2-1.5a1.5 1.5 0 0 1 2.7 1.3L18 13M7 22H4a2 2 0 0 1-2-2V12a2 2 0 0 1 2-2h3'/%3E%3C/svg%3E"); }
|
||||
.ic-share { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2'%3E%3Cpath d='M4 12v7a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7M16 6l-4-4-4 4M12 2v13'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2'%3E%3Cpath d='M4 12v7a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7M16 6l-4-4-4 4M12 2v13'/%3E%3C/svg%3E"); }
|
||||
.ic-cmt { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2'%3E%3Cpath d='M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='2'%3E%3Cpath d='M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z'/%3E%3C/svg%3E"); }
|
||||
|
||||
@@ -61,7 +61,7 @@ export default function ContentDetail() {
|
||||
<Text className="cd-title">{item.title}</Text>
|
||||
<View className="cd-meta-row">
|
||||
{item.publisher_avatar ? <Image className="cd-ava" src={item.publisher_avatar} mode="aspectFill" /> : <View className="cd-ava" />}
|
||||
<Text className="cd-author">{author}<Text className="cd-badge">✓</Text></Text>
|
||||
<Text className="cd-author">{author}</Text><View className="ic ic-check cd-badge-ic" />
|
||||
</View>
|
||||
<View className="cd-meta-line">
|
||||
<Text className="cd-meta-at">{rw(item.created_at)}</Text>
|
||||
@@ -87,13 +87,13 @@ export default function ContentDetail() {
|
||||
<View className="cd-bar">
|
||||
<View className="cd-bar-left">
|
||||
{item.publisher_avatar ? <Image className="cd-ava2" src={item.publisher_avatar} mode="aspectFill" /> : <View className="cd-ava2" />}
|
||||
<Text className="cd-author">{author}<Text className="cd-badge">✓</Text></Text>
|
||||
<Text className="cd-author">{author}</Text><View className="ic ic-check cd-badge-ic" />
|
||||
</View>
|
||||
<View className="cd-bar-actions">
|
||||
<View className="cd-act" onClick={() => setLike((v) => !v)}><Text className={like ? 'cd-act-ic on' : 'cd-act-ic'}>👍</Text><Text className="cd-act-n">{like ? 1 : 0}</Text></View>
|
||||
<View className="cd-act" onClick={copyLink}><Text className="cd-act-ic">↗</Text><Text className="cd-act-n">转发</Text></View>
|
||||
<View className="cd-act" onClick={() => setFav((v) => !v)}><Text className={fav ? 'cd-act-ic on' : 'cd-act-ic'}>♥</Text></View>
|
||||
<View className="cd-act" onClick={scrollToComment}><Text className="cd-act-ic">✎</Text><Text className="cd-act-n">留言</Text></View>
|
||||
<View className="cd-act" onClick={() => setLike((v) => !v)}><View className={`ic ic-thumb cd-act-ic${like ? ' on' : ''}`} /><Text className="cd-act-n">{like ? 1 : 0}</Text></View>
|
||||
<View className="cd-act" onClick={copyLink}><View className="ic ic-share cd-act-ic" /><Text className="cd-act-n">转发</Text></View>
|
||||
<View className="cd-act" onClick={() => setFav((v) => !v)}><View className={`ic ic-heart cd-act-ic${fav ? ' on' : ''}`} /></View>
|
||||
<View className="cd-act" onClick={scrollToComment}><View className="ic ic-cmt cd-act-ic" /><Text className="cd-act-n">留言</Text></View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -103,7 +103,7 @@ export default function ContentDetail() {
|
||||
<Text className="cd-cmt-title">留言</Text>
|
||||
<View className="cd-cmt-input">
|
||||
<Input className="cd-cmt-field" placeholder="写留言…" value={draft} onInput={(e) => setDraft(e.detail.value)} />
|
||||
<View className="cd-cmt-tools"><Text>😊</Text><Text>🖼</Text></View>
|
||||
<View className="cd-cmt-tools"><View className="ic ic-cmt" /></View>
|
||||
<Button className="btn btn-sm cd-cmt-send" disabled={sending || !draft.trim()} onClick={send}>发送</Button>
|
||||
</View>
|
||||
{comments.length === 0
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
.cd-ava { width: 36rpx; height: 36rpx; border-radius: 50%; background: linear-gradient(135deg, #555, #333); flex-shrink: 0; }
|
||||
.cd-ava2 { width: 44rpx; height: 44rpx; border-radius: 50%; background: linear-gradient(135deg, #555, #333); flex-shrink: 0; }
|
||||
.cd-author { font-size: 25rpx; color: #c4c2c3; display: inline-flex; align-items: center; gap: 4rpx; }
|
||||
.cd-badge { font-size: 22rpx; color: #26a69a; }
|
||||
.cd-badge-ic { width: 22rpx; height: 22rpx; color: #26a69a; margin-left: 6rpx; }
|
||||
.cd-act-ic { width: 34rpx; height: 34rpx; color: #cfcfd2; }
|
||||
.cd-act-ic.on { color: #3b82f6; }
|
||||
.cd-meta-line { display: flex; align-items: center; gap: 8rpx; padding: 8rpx 28rpx 0; }
|
||||
.cd-meta-at { font-size: 23rpx; color: #7c7c80; }
|
||||
.cd-dot { font-size: 23rpx; color: #6d6d72; }
|
||||
|
||||
@@ -65,7 +65,7 @@ function CardBig({ it, go, liked, onLike }) {
|
||||
<View className="ct-card">
|
||||
<View className="ct-cover" style={img ? undefined : { background: `linear-gradient(135deg, ${m.from}, ${m.to})` }} onClick={() => go(it.id)}>
|
||||
{img ? <Image className="ct-cover-img" src={img} mode="aspectFill" /> : <Text className="ct-thumb-char">{m.label[0]}</Text>}
|
||||
{it.video && <View className="ct-play">▶</View>}
|
||||
{it.video && <View className="ct-play"><View className="ic ic-play" /></View>}
|
||||
</View>
|
||||
<View className="ct-card-bd">
|
||||
<Text className="ct-card-title" onClick={() => go(it.id)}>{it.title}</Text>
|
||||
@@ -75,7 +75,7 @@ function CardBig({ it, go, liked, onLike }) {
|
||||
<Text className="ct-dot">·</Text>
|
||||
<Text className="ct-time">{timeAgo(it.created_at)}</Text>
|
||||
<View className={`ct-like${liked ? ' on' : ''}`} onClick={(e) => { e.stopPropagation(); onLike(it.id); }}>
|
||||
<Text className="ct-like-ic">{liked ? '♥' : '♡'}</Text>
|
||||
<View className="ic ic-heart" />
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
@@ -104,8 +104,6 @@ export default function ContentIndex() {
|
||||
const goQuiz = () => Taro.navigateTo({ url: '/pages/policy/index' });
|
||||
const toggleLike = (id) => setLiked((m) => ({ ...m, [id]: !m[id] }));
|
||||
|
||||
const featured = (i) => i % 3 === 0;
|
||||
|
||||
return (
|
||||
<View className="ct page-in">
|
||||
{/* 类别分段 */}
|
||||
@@ -127,7 +125,7 @@ export default function ContentIndex() {
|
||||
{loaded ? (
|
||||
items.length === 0
|
||||
? <View className="ct-empty"><Text>暂无{CONTENT_CATS.find((c) => c.key === cat)?.label || ''}内容</Text></View>
|
||||
: items.map((it, i) => featured(i)
|
||||
: items.map((it) => it.card_mode === "big"
|
||||
? <CardBig key={it.id} it={it} go={go} liked={!!liked[it.id]} onLike={toggleLike} />
|
||||
: <CardRow key={it.id} it={it} go={go} />)
|
||||
) : (
|
||||
|
||||
@@ -43,10 +43,11 @@
|
||||
.ct-cover-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
|
||||
.ct-play { position: relative; z-index: 2; }
|
||||
.ct-play {
|
||||
width: 72rpx; height: 72rpx; border-radius: 50%; background: rgba(255,255,255,.9);
|
||||
color: #111; font-size: 30rpx; display: flex; align-items: center; justify-content: center;
|
||||
position: relative; z-index: 2; width: 72rpx; height: 72rpx; border-radius: 50%; background: rgba(255,255,255,.9);
|
||||
color: #111; display: flex; align-items: center; justify-content: center;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0,0,0,.4);
|
||||
}
|
||||
.ct-play .ic { width: 38rpx; height: 38rpx; color: #111; }
|
||||
.ct-card-bd { padding: 20rpx 22rpx 8rpx; }
|
||||
.ct-card-title {
|
||||
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
||||
@@ -54,8 +55,8 @@
|
||||
}
|
||||
.ct-card-ad { display: flex; align-items: center; gap: 8rpx; margin-top: 16rpx; padding-bottom: 22rpx; }
|
||||
.ct-like { margin-left: auto; width: 56rpx; height: 56rpx; border-radius: 50%; background: #1d1d22; display: flex; align-items: center; justify-content: center; }
|
||||
.ct-like-ic { font-size: 30rpx; color: #9b9b9b; }
|
||||
.ct-like.on .ct-like-ic { color: #ff3b5c; }
|
||||
.ct-like .ic { width: 30rpx; height: 30rpx; color: #9b9b9b; }
|
||||
.ct-like.on .ic { color: #ff3b5c; }
|
||||
.ct-like.on { background: #2a1520; }
|
||||
|
||||
.ct-empty { padding: 80rpx 0; text-align: center; font-size: 26rpx; color: #8e8e8e; }
|
||||
|
||||
Reference in New Issue
Block a user