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:
@@ -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>
|
<text class="mt-2 text-sm text-gray-500">{{disallowComment ? '暂无评论' : '暂无评论'}}</text>
|
||||||
<wd-icon name="empty" size="100rpx" class="text-primary" />
|
<view v-if="disallowComment" class="mt-2 text-xs text-red-400">
|
||||||
</template>
|
文章已开启禁止评论
|
||||||
<template #bottom>
|
</view>
|
||||||
<text class="mt-2 text-sm text-gray-500">{{disallowComment ? '暂无评论' : '暂无评论'}}</text>
|
<view v-else class="mt-2 bg-primary text-black text-sm px-4 py-1.5 rounded-lg"
|
||||||
<view v-if="disallowComment" class="mt-2 text-xs text-red-400">
|
@click="handleToComment()">
|
||||||
文章已开启禁止评论
|
抢沙发
|
||||||
</view>
|
</view>
|
||||||
<view v-else class="mt-2 bg-primary text-black text-sm px-4 py-1.5 rounded-lg" @click="handleToComment()">
|
|
||||||
抢沙发
|
|
||||||
</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>
|
|
||||||
@@ -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
@@ -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),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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 }}
|
||||||
|
|||||||
Reference in New Issue
Block a user