1
0
mirror of https://github.com/ialley-workshop-open/uni-halo.git synced 2026-09-12 16:40:40 +08:00

style,refactor,feat: 统一卡片布局为图片在上并优化细节

1. 调整全局默认卡片样式为image_top,更新各页面默认布局配置
2. 给文章卡片添加variant属性适配双列/单列布局
3. 优化文章内容区域文字样式与评论列表空状态
4. 简化快捷导航组件代码,移除冗余样式与多余props
5. 优化markdown渲染配置与评论头像空格格式
This commit is contained in:
小莫唐尼
2026-09-09 17:47:54 +08:00
parent b41e01106a
commit d528d214b5
9 changed files with 32 additions and 62 deletions
+6 -5
View File
@@ -43,9 +43,9 @@ layout: {
| 页面 | listLayout | cardType | | 页面 | listLayout | cardType |
|------|-----------|----------| |------|-----------|----------|
| home(首页) | `single` | `image_bottom` | | home(首页) | `single` | `image_top` |
| articles(文章列表) | `double` | `image_bottom` | | articles(文章列表) | `double` | `image_top` |
| archives(文章归档) | `single` | `image_bottom` | | archives(文章归档) | `single` | `image_top` |
## 3. 后端插件字段映射(getConfigs.preferences) ## 3. 后端插件字段映射(getConfigs.preferences)
@@ -73,7 +73,7 @@ layout: {
| `src/pages/tabbar/home/home.vue` | `layout.home.listLayout` 决定容器单/双列;卡片 `from="home"``layout.home.cardType` | | `src/pages/tabbar/home/home.vue` | `layout.home.listLayout` 决定容器单/双列;卡片 `from="home"``layout.home.cardType` |
| `src/pages-blog/articles/articles.vue` | `layout.articles.listLayout` 决定容器与 `variant`(grid/list);卡片 `from="articles"` | | `src/pages-blog/articles/articles.vue` | `layout.articles.listLayout` 决定容器与 `variant`(grid/list);卡片 `from="articles"` |
| `src/pages-blog/archives/archives.vue` | `layout.archives.listLayout` 决定归档时间线内单/双列;卡片 `from="archives"` | | `src/pages-blog/archives/archives.vue` | `layout.archives.listLayout` 决定归档时间线内单/双列;卡片 `from="archives"` |
| `src/components/uh-article-card/uh-article-card.vue` | 按 `from` 读取对应页面 `cardType` 作为 layout;grid/双列窄列自动回退 `image_top`;非法值兜底 `image_bottom` | | `src/components/uh-article-card/uh-article-card.vue` | 按 `from` 读取对应页面 `cardType` 作为 layout;grid/双列窄列自动回退 `image_top`;非法值兜底 `image_top` |
## 5. 设置页枚举(「默认」= 跟随站点默认) ## 5. 设置页枚举(「默认」= 跟随站点默认)
@@ -85,5 +85,6 @@ layout: {
| 版本 | 变更 | | 版本 | 变更 |
|------|------| |------|------|
| v2.4 | 卡片样式值体系由旧 `lr_*/tb_*` 改为组件 layout 值 `image_top/image_right/image_bottom/image_left`;内置默认 cardType 统一为 `image_bottom`;移除 `uh-article-card` 旧值映射(`CARD_TYPE_TO_LAYOUT`),非法值兜底 `image_bottom` | | v2.5 | 内置默认 cardType 统一为 `image_top`;组件非法值兜底同步为 `image_top` |
| v2.4 | 卡片样式值体系由旧 `lr_*/tb_*` 改为组件 layout 值 `image_top/image_right/image_bottom/image_left`;移除 `uh-article-card` 旧值映射(`CARD_TYPE_TO_LAYOUT`) |
| v2.3 | 布局偏好由全局 `layout.home` / `layout.cardType`(字符串)重构为按页面分组 `layout.{home,articles,archives}.{listLayout,cardType}`;设置页增加「布局 / 功能」分段器与页面分组设置项;三个消费页面联动卡片 | | v2.3 | 布局偏好由全局 `layout.home` / `layout.cardType`(字符串)重构为按页面分组 `layout.{home,articles,archives}.{listLayout,cardType}`;设置页增加「布局 / 功能」分段器与页面分组设置项;三个消费页面联动卡片 |
@@ -117,7 +117,7 @@
return raw return raw
}) })
const cardLayout = computed(() => CARD_LAYOUTS[effectiveLayout.value] ?? CARD_LAYOUTS.image_bottom) const cardLayout = computed(() => CARD_LAYOUTS[effectiveLayout.value] ?? CARD_LAYOUTS.image_top)
/** 社交卡片形态(封面在下):左上用户信息(头像 + 昵称/日期垂直)、右上浏览数 */ /** 社交卡片形态(封面在下):左上用户信息(头像 + 昵称/日期垂直)、右上浏览数 */
const isSocialCard = computed(() => effectiveLayout.value === 'image_bottom') const isSocialCard = computed(() => effectiveLayout.value === 'image_bottom')
@@ -183,7 +183,7 @@
</template> </template>
</view> </view>
<view class="flex items-center text-xs text-gray-500" :class="cardLayout.footer"> <view class="flex items-center text-xs text-gray-500" :class="cardLayout.footer">
<view v-if="!isGrid" class="flex items-center" :class="cardLayout.authorGroup"> <view class="flex items-center" :class="cardLayout.authorGroup">
<image :src="article.owner.avatar" class="uh-global-card-glass h-5 w-5 rounded-full" <image :src="article.owner.avatar" class="uh-global-card-glass h-5 w-5 rounded-full"
:class="cardLayout.avatar" mode="aspectFill" /> :class="cardLayout.avatar" mode="aspectFill" />
<template v-if="isSocialCard"> <template v-if="isSocialCard">
@@ -199,11 +199,11 @@
</view> </view>
</view> </view>
</template> </template>
<text v-else class="truncate">{{ article.owner.displayName }}</text> <text v-else class="min-w-0 flex-1 truncate">{{ article.owner.displayName }}</text>
</view> </view>
<text v-if="!isGrid && !isSocialCard" class="text-gray-400" <text v-if="!isGrid && !isSocialCard" class="text-gray-400"
:class="cardLayout.time">{{ publishTimeText }}</text> :class="cardLayout.time">{{ publishTimeText }}</text>
<view v-if="!isSocialCard" class="visits flex items-center gap-x-1" :class="cardLayout.visits"> <view v-if="!isGrid && !isSocialCard" class="visits flex items-center gap-x-1" :class="cardLayout.visits">
浏览 浏览
<text class="number">{{ visitCount }}</text> <text class="number">{{ visitCount }}</text>
@@ -39,7 +39,7 @@
result.value = res.data result.value = res.data
dataList.value = res.data.items.map((item) => { dataList.value = res.data.items.map((item) => {
// todo:临时 // todo:临时
item.spec.owner.avatar = checkAvatarUrl(item.spec.owner.avatar??'https://api.dicebear.com/10.x/adventurer-neutral/svg') item.spec.owner.avatar = checkAvatarUrl(item.spec.owner.avatar ?? 'https://api.dicebear.com/10.x/adventurer-neutral/svg')
return item return item
}) })
loading.value = 'success' loading.value = 'success'
@@ -101,8 +101,7 @@
<uh-section-title> <uh-section-title>
评论列表 评论列表
<template #right> <template #right>
<view class="flex items-center gap-1.5 text-xs text-gray-500 font-normal" <view class="flex items-center gap-1.5 text-xs text-gray-500 font-normal" @click="handleGetData">
@click="handleGetData">
<wd-icon name="refresh" size="28rpx" /> <wd-icon name="refresh" size="28rpx" />
<text class="">刷新</text> <text class="">刷新</text>
</view> </view>
@@ -135,20 +134,15 @@
<view v-if="dataList.length === 0" class="empty py-12"> <view v-if="dataList.length === 0" class="empty py-12">
<view class="empty-box flex flex-col items-center"> <view class="empty-box flex flex-col items-center">
<wd-empty> <wd-icon class-prefix="uhemoji-icon" name="-confused" size="100rpx" class="text-primary" />
<template #image>
<wd-icon name="empty" size="100rpx" class="text-primary" />
</template>
<template #bottom>
<text class="mt-2 text-sm text-gray-500">{{disallowComment ? '暂无评论' : '暂无评论'}}</text> <text class="mt-2 text-sm text-gray-500">{{disallowComment ? '暂无评论' : '暂无评论'}}</text>
<view v-if="disallowComment" class="mt-2 text-xs text-red-400"> <view v-if="disallowComment" class="mt-2 text-xs text-red-400">
文章已开启禁止评论 文章已开启禁止评论
</view> </view>
<view v-else class="mt-2 bg-primary text-black text-sm px-4 py-1.5 rounded-lg" @click="handleToComment()"> <view v-else class="mt-2 bg-primary text-black text-sm px-4 py-1.5 rounded-lg"
@click="handleToComment()">
抢沙发 抢沙发
</view> </view>
</template>
</wd-empty>
</view> </view>
</view> </view>
@@ -96,7 +96,7 @@
:style="{ :style="{
backgroundColor: item.bgGlass backgroundColor: item.bgGlass
}"> }">
<wd-icon :class-prefix="item.iconPrefix" :name="item.icon" size="64rpx" :color="item.color" /> <wd-icon :class-prefix="item.iconPrefix" :name="item.icon" size="64rpx"/>
</view> </view>
<view class="text-xs text-gray-900"> <view class="text-xs text-gray-900">
{{ item.title }} {{ item.title }}
@@ -105,16 +105,3 @@
</view> </view>
</view> </view>
</template> </template>
<style scoped lang="scss">
/* 彩色玻璃图标:低透明度同色底 + 同色描边 + 柔和同色投影,图标用实体色保证通透感 */
.quick-nav-icon {
backdrop-filter: blur(16rpx) saturate(160%);
-webkit-backdrop-filter: blur(16rpx) saturate(160%);
/* 低端安卓 WebView 不支持 backdrop-filter 的兜底:提高底色不透明度保证可读性 */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
background-color: rgb(255 255 255 / 60%) !important;
}
}
</style>
+3 -3
View File
@@ -63,9 +63,9 @@ export const DefaultAppSettings: IAppSettings = {
dotPosition: 'right', dotPosition: 'right',
}, },
layout: { layout: {
home: { listLayout: 'single', cardType: 'image_bottom' }, home: { listLayout: 'single', cardType: 'image_top' },
articles: { listLayout: 'double', cardType: 'image_bottom' }, articles: { listLayout: 'double', cardType: 'image_top' },
archives: { listLayout: 'single', cardType: 'image_bottom' }, archives: { listLayout: 'single', cardType: 'image_top' },
}, },
ad: { ad: {
timeout: 3, timeout: 3,
+3 -16
View File
@@ -1,16 +1,9 @@
/**
* mp-html 富文本 / markdown 渲染业务配置
* 源自旧项目 common/markdown/markdown.config.js,TS 化复刻(业务封装新建,插件本体走 npm mp-html)
* 用法:<mp-html :content="html" :tag-style="markdownConfig.tagStyle" :container-style="markdownConfig.containStyle" />
*/
import { checkImageUrl } from '@/utils/url' import { checkImageUrl } from '@/utils/url'
const primaryColor = '#B9E424' const primaryColor = '#B9E424'
export const markdownConfig = { export const markdownConfig = {
/** 图片域名前缀(mp-html 相对路径补全,源自旧配置 domain: BASE_API) */
domain: import.meta.env.VITE_SERVER_BASEURL || '', domain: import.meta.env.VITE_SERVER_BASEURL || '',
/** 标签样式定制(表格/引用/标题/代码等) */
tagStyle: { tagStyle: {
table: ` table: `
table-layout: fixed; table-layout: fixed;
@@ -25,13 +18,9 @@ export const markdownConfig = {
`, `,
th: ` th: `
padding: 8px; padding: 8px;
border-right: 1px solid var(--classE);
border-bottom: 1px solid var(--classE);
`, `,
td: ` td: `
padding: 8px; padding: 8px;
border-right: 1px solid var(--classE);
border-bottom: 1px solid var(--classE);
`, `,
blockquote: ` blockquote: `
padding: 8px 15px; padding: 8px 15px;
@@ -66,7 +55,7 @@ export const markdownConfig = {
color: ${primaryColor}; color: ${primaryColor};
line-height: 24px; line-height: 24px;
position: relative; position: relative;
margin: 26px 0 18px; margin: 20px 0 14px;
font-size: 1.14em; font-size: 1.14em;
`, `,
h4: ` h4: `
@@ -93,15 +82,13 @@ export const markdownConfig = {
p: ` p: `
line-height: 1.65; line-height: 1.65;
margin-bottom: 14px; margin-bottom: 14px;
font-size: 14px;
`, `,
code: ' ', code: ' ',
strong: 'font-weight: 700;color: rgb(248, 57, 41);', strong: 'font-weight: 700;color: rgb(248, 57, 41);',
img: 'border-radius: 10px',
video: 'width: 100%', video: 'width: 100%',
}, },
/** 容器样式 */ containStyle: 'padding:0;background-color:transparent;',
containStyle: 'font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;padding:0;font-size: 14px;color: #606266;word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 0px;background-color:transparent;',
/** 加载图 / 空图(来自应用配置 imagesConfig) */
loadingGif: checkImageUrl(undefined), loadingGif: checkImageUrl(undefined),
emptyGif: checkImageUrl(undefined), emptyGif: checkImageUrl(undefined),
} }
+1
View File
@@ -282,6 +282,7 @@ onReachBottom(() => {
v-for="post in item.posts" v-for="post in item.posts"
:key="post.metadata.name" :key="post.metadata.name"
from="archives" from="archives"
:variant="archivesListLayout === 'double' ? 'grid' : 'list'"
:article="post" :article="post"
:audit-mode="calcAuditModeEnabled" :audit-mode="calcAuditModeEnabled"
/> />
@@ -539,7 +539,7 @@
</view> </view>
<!-- 内容区域 --> <!-- 内容区域 -->
<view class="box-border flex flex-col gap-y-3 p-3"> <view class="box-border flex flex-col gap-y-3 p-3 text-gray-900 text-sm">
<!-- 受限阅读 --> <!-- 受限阅读 -->
<template v-if="checkPostRestrictRead(result!)"> <template v-if="checkPostRestrictRead(result!)">
<view v-if="showContentArr.length === 0"> <view v-if="showContentArr.length === 0">
+1 -1
View File
@@ -249,7 +249,7 @@
<view class="box-border p-3 pt-0" <view class="box-border p-3 pt-0"
:class="homeListLayout === 'double' ? 'grid grid-cols-2 gap-3' : 'flex flex-col gap-y-3'"> :class="homeListLayout === 'double' ? 'grid grid-cols-2 gap-3' : 'flex flex-col gap-y-3'">
<uh-article-card v-for="(article, index) in articleList" :key="index" from="home" :article="article" <uh-article-card v-for="(article, index) in articleList" :key="index" from="home" :article="article"
:audit-mode="calcAuditModeEnabled" /> :variant="homeListLayout === 'double' ? 'grid' : 'list'" :audit-mode="calcAuditModeEnabled" />
</view> </view>
<view class="mt-3 box-border pb-5 text-center text-xs text-gray-400"> <view class="mt-3 box-border pb-5 text-center text-xs text-gray-400">
{{ loadMoreText }} {{ loadMoreText }}