mirror of
https://github.com/ialley-workshop-open/uni-halo.git
synced 2026-09-12 16:40:40 +08:00
refactor: 整体项目样式与组件优化升级
主要变更: 1. 新增uhemoji2图标字体库并全局引入 2. 重构导航组件与页面布局,统一使用自定义导航栏 3. 替换旧图标为emoji图标,统一视觉风格 4. 清理冗余调试代码与注释 5. 优化快捷导航、关于页等页面样式与交互 6. 修复滚动到顶部组件黑名单配置
This commit is contained in:
@@ -295,7 +295,85 @@ onLoad(() => {
|
|||||||
- 页面根节点用 `app-page` 类 + 主题底色:`<view class="app-page min-h-screen w-screen flex flex-col bg-page">`
|
- 页面根节点用 `app-page` 类 + 主题底色:`<view class="app-page min-h-screen w-screen flex flex-col bg-page">`
|
||||||
- 页面标题 `navigationBarTitleText` 写中文;下拉刷新 `enablePullDownRefresh: true`
|
- 页面标题 `navigationBarTitleText` 写中文;下拉刷新 `enablePullDownRefresh: true`
|
||||||
|
|
||||||
### 5.4 页面数据请求(统一 updateLoadingStatus + uh-data-loading 组件)
|
### 5.4 子页面自定义导航(uh-navbar 组件)
|
||||||
|
|
||||||
|
**用途**:子页面(非 tabbar 页,如文章详情、设置、投票详情等)的顶部自定义导航栏。
|
||||||
|
配合页面 `navigationStyle: 'custom'` 使用,**新页面一律使用它,不要用默认导航栏**。
|
||||||
|
|
||||||
|
**前提(definePage 里必须声明)**:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
definePage({
|
||||||
|
style: {
|
||||||
|
navigationStyle: 'custom', // 关闭系统默认导航栏,让位给 uh-navbar
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
**Props 一览**:
|
||||||
|
|
||||||
|
| Prop | 类型 | 默认值 | 说明 |
|
||||||
|
|------|------|--------|------|
|
||||||
|
| `use-back` | `boolean` | `true` | 是否显示左侧返回按钮 |
|
||||||
|
| `use-title` | `boolean` | `true` | 是否显示标题 |
|
||||||
|
| `default-title` | `string` | - | 默认标题(顶部文案) |
|
||||||
|
| `title-color` | `string` | - | 标题颜色类名(如 `text-gray-900`),**带此属性时固定颜色、不随滚动变色** |
|
||||||
|
| `scroll-title` | `string` | - | 滚动后标题(配合 default-title:顶部显示默认标题,滚过 50% 换 scroll-title) |
|
||||||
|
| `need-placeholder` | `boolean` | `true` | 是否生成占位(为页面内容让出导航高度) |
|
||||||
|
|
||||||
|
**页面结构模板**(参考 `src/pages-blog/test/test.vue`):
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<script lang="ts" setup>
|
||||||
|
definePage({
|
||||||
|
style: {
|
||||||
|
navigationBarTitleText: '测试页面',
|
||||||
|
navigationStyle: 'custom', // 使用 uh-navbar 必须声明
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const { loadingStatus, updateLoadingStatus } = useDataLoadingStatus()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<!-- 最外层仅作容器(bg-page 底色),不设 padding -->
|
||||||
|
<view class="w-full min-h-screen bg-page">
|
||||||
|
<!-- 导航栏:置于页面最顶部,内置占位/安全区处理 -->
|
||||||
|
<uh-navbar default-title="测试页面" :need-placeholder="true" title-color="text-gray-900" />
|
||||||
|
|
||||||
|
<!-- 内容区:从这开始写,因为 uh-navbar 已内置占位(need-placeholder=true) -->
|
||||||
|
<view class="box-border px-3">
|
||||||
|
<uh-data-loading v-if="loadingStatus !== DataLoadingStatusEnum.Success" :loading-status="loadingStatus" min-height="80vh" />
|
||||||
|
<view v-else>
|
||||||
|
请求成功啦
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
**使用要点**:
|
||||||
|
|
||||||
|
- **`need-placeholder` 必须按场景传对**:
|
||||||
|
- 页面内容直接从导航下开始(普通子页面)→ `:need-placeholder="true"`(默认即可,如 test.vue / setting.vue)
|
||||||
|
- 页面顶部有全屏封面/背景图,内容要盖到导航下面 → `:need-placeholder="false"`(如 article-detail.vue,封面 `pt-72` 上移)
|
||||||
|
- **`title-color` 与 `scroll-title` 二选一**:
|
||||||
|
- 页面底色非深色 → 传 `title-color="text-gray-900"`(固定深色,如 test.vue / setting.vue)
|
||||||
|
- 不传时标题会随滚动变白→深灰(顶部透明、滚后加深),适合顶部是深色大图的场景(如 article-detail.vue 只传 `default-title` + `scroll-title`,让滚动变色)
|
||||||
|
- 中间标题可用**默认插槽覆盖**(不传则显示 `default-title`/`scroll-title`),右侧扩展用 **`#right` 插槽**:
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<uh-navbar default-title="偏好设置" :need-placeholder="true">
|
||||||
|
<template #right>
|
||||||
|
<view @click="handleSave">保存</view>
|
||||||
|
</template>
|
||||||
|
</uh-navbar>
|
||||||
|
```
|
||||||
|
|
||||||
|
- 返回按钮内置(`uni.navigateBack`),无需自写
|
||||||
|
- easycom 已配置 `uh-` 前缀,直接用 `<uh-navbar />`,**无需 import**
|
||||||
|
|
||||||
|
### 5.5 页面数据请求(统一 updateLoadingStatus + uh-data-loading 组件)
|
||||||
|
|
||||||
**数据加载四态**:`loading / error / empty / success`,统一用
|
**数据加载四态**:`loading / error / empty / success`,统一用
|
||||||
`useDataLoadingStatus`(`src/hooks/useDataLoadingStatus.ts`)的
|
`useDataLoadingStatus`(`src/hooks/useDataLoadingStatus.ts`)的
|
||||||
@@ -419,7 +497,7 @@ onReachBottom(() => {
|
|||||||
列表页/四态展示优先 `updateLoadingStatus` 写法
|
列表页/四态展示优先 `updateLoadingStatus` 写法
|
||||||
- 简单场景也可用 `useRequest(fn, { immediate })`:返回 `{ loading, error, data, run }`
|
- 简单场景也可用 `useRequest(fn, { immediate })`:返回 `{ loading, error, data, run }`
|
||||||
|
|
||||||
### 5.5 列表页(分页加载)
|
### 5.6 列表页(分页加载)
|
||||||
|
|
||||||
列表页可用 z-paging(easycom 已配置 `<z-paging>` 直接用)或手写分页。
|
列表页可用 z-paging(easycom 已配置 `<z-paging>` 直接用)或手写分页。
|
||||||
手写分页的既有模式(参考 `src/pages/tabbar/home/home.vue`、`pages-blog/votes/votes.vue`):
|
手写分页的既有模式(参考 `src/pages/tabbar/home/home.vue`、`pages-blog/votes/votes.vue`):
|
||||||
@@ -457,7 +535,7 @@ onReachBottom(() => {
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
### 5.6 依赖插件的页面(插件可用性 + 维护拦截)
|
### 5.7 依赖插件的页面(插件可用性 + 维护拦截)
|
||||||
|
|
||||||
Halo 是插件化 CMS,页面可能依赖插件(投票 plugin-vote、瞬间 PluginMoments 等):
|
Halo 是插件化 CMS,页面可能依赖插件(投票 plugin-vote、瞬间 PluginMoments 等):
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ async function fetchNotices() {
|
|||||||
|
|
||||||
/** 点击单条公告标题 → 详情页 */
|
/** 点击单条公告标题 → 详情页 */
|
||||||
function handleTap(item : INoticeListVo) {
|
function handleTap(item : INoticeListVo) {
|
||||||
if (!item.name)
|
if (!item.name) { return }
|
||||||
return
|
|
||||||
uni.navigateTo({ url: `/pages-blog/notice/detail?name=${item.name}` })
|
uni.navigateTo({ url: `/pages-blog/notice/detail?name=${item.name}` })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,49 +37,29 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view
|
<view v-if="showList.length > 0"
|
||||||
v-if="showList.length > 0"
|
class="uh-global-card-glass box-border mx-3 mt-3 mb-2 flex items-center rounded-xl px-3">
|
||||||
class="uh-global-card-glass box-border mx-3 mt-3 mb-2 flex items-center rounded-xl px-3"
|
|
||||||
>
|
|
||||||
<!-- 左侧公告入口 -->
|
<!-- 左侧公告入口 -->
|
||||||
<view class="flex shrink-0 items-center gap-1 py-2 pr-3" @click="handleGoList">
|
<view class="flex shrink-0 items-center gap-2 py-2 pr-3" @click="handleGoList">
|
||||||
<text class="text-sm">
|
<wd-icon class-prefix="uhemoji2-icon" name="-happy-" size="36rpx" />
|
||||||
📢
|
<text class="text-sm font-bold text-red-400">
|
||||||
</text>
|
|
||||||
<text class="text-xs font-bold text-red-400">
|
|
||||||
公告
|
公告
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 标题轮播(仅一条时静态展示) -->
|
<!-- 标题轮播(仅一条时静态展示) -->
|
||||||
<view class="h-[60rpx] min-w-0 flex-1 overflow-hidden">
|
<view class="h-[60rpx] min-w-0 flex-1 overflow-hidden">
|
||||||
<swiper
|
<swiper v-if="showList.length > 1" class="h-full w-full" vertical circular autoplay :interval="3500"
|
||||||
v-if="showList.length > 1"
|
:duration="400">
|
||||||
class="h-full w-full"
|
<swiper-item v-for="(item, index) in showList" :key="item.name || index" class="h-full w-full">
|
||||||
vertical
|
<view class="flex h-full w-full items-center truncate text-xs text-gray-500"
|
||||||
circular
|
@click="handleTap(item)">
|
||||||
autoplay
|
|
||||||
:interval="3500"
|
|
||||||
:duration="400"
|
|
||||||
>
|
|
||||||
<swiper-item
|
|
||||||
v-for="(item, index) in showList"
|
|
||||||
:key="item.name || index"
|
|
||||||
class="h-full w-full"
|
|
||||||
>
|
|
||||||
<view
|
|
||||||
class="flex h-full w-full items-center truncate text-xs text-gray-500"
|
|
||||||
@click="handleTap(item)"
|
|
||||||
>
|
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</view>
|
</view>
|
||||||
</swiper-item>
|
</swiper-item>
|
||||||
</swiper>
|
</swiper>
|
||||||
<view
|
<view v-else class="flex h-full w-full items-center truncate text-[24rpx] text-[#555]"
|
||||||
v-else
|
@click="handleTap(showList[0])">
|
||||||
class="flex h-full w-full items-center truncate text-[24rpx] text-[#555]"
|
|
||||||
@click="handleTap(showList[0])"
|
|
||||||
>
|
|
||||||
{{ showList[0]?.title }}
|
{{ showList[0]?.title }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -14,20 +14,27 @@
|
|||||||
const navList = computed(() => {
|
const navList = computed(() => {
|
||||||
const loveEnabled = !!(haloConfigs.value.loveConfig as { loveEnabled ?: boolean })?.loveEnabled
|
const loveEnabled = !!(haloConfigs.value.loveConfig as { loveEnabled ?: boolean })?.loveEnabled
|
||||||
const socialEnabled = !!(haloConfigs.value.authorConfig?.social as { enabled ?: boolean } | undefined)?.enabled
|
const socialEnabled = !!(haloConfigs.value.authorConfig?.social as { enabled ?: boolean } | undefined)?.enabled
|
||||||
|
// <wd-icon class-prefix="uhemoji-icon" name="-smile-" size="32rpx" />
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
key: 'archives',
|
key: 'archives',
|
||||||
title: calcAuditModeEnabled.value ? '内容归档' : '文章归档',
|
title: calcAuditModeEnabled.value ? '内容归档' : '文章归档',
|
||||||
bgColor: 'rgba(3, 169, 244, 0.95)',
|
color: '#03A9F4',
|
||||||
icon: 'news',
|
bgGlass: 'rgba(3, 169, 244, 0.14)',
|
||||||
|
borderColor: 'rgba(3, 169, 244, 0.35)',
|
||||||
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-mask',
|
||||||
path: '/pages-blog/archives/archives',
|
path: '/pages-blog/archives/archives',
|
||||||
show: true,
|
show: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'vote',
|
key: 'vote',
|
||||||
title: '投票中心',
|
title: '投票中心',
|
||||||
bgColor: 'rgba(0, 188, 212, 0.95)',
|
color: '#00BCD4',
|
||||||
icon: 'box',
|
bgGlass: 'rgba(0, 188, 212, 0.14)',
|
||||||
|
borderColor: 'rgba(0, 188, 212, 0.35)',
|
||||||
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-confused',
|
||||||
path: '/pages-blog/votes/votes',
|
path: '/pages-blog/votes/votes',
|
||||||
// show: !calcAuditModeEnabled.value && calcVotePluginEnabled.value,
|
// show: !calcAuditModeEnabled.value && calcVotePluginEnabled.value,
|
||||||
show: true,
|
show: true,
|
||||||
@@ -35,8 +42,11 @@
|
|||||||
{
|
{
|
||||||
key: 'disclaimers',
|
key: 'disclaimers',
|
||||||
title: '友情链接',
|
title: '友情链接',
|
||||||
bgColor: 'rgba(0, 150, 136, 0.95)',
|
color: '#009688',
|
||||||
icon: 'link',
|
bgGlass: 'rgba(0, 150, 136, 0.14)',
|
||||||
|
borderColor: 'rgba(0, 150, 136, 0.35)',
|
||||||
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-wink',
|
||||||
path: '/pages-blog/friend-links/friend-links',
|
path: '/pages-blog/friend-links/friend-links',
|
||||||
// show: calcLinksPluginEnabled.value,
|
// show: calcLinksPluginEnabled.value,
|
||||||
show: true,
|
show: true,
|
||||||
@@ -44,8 +54,11 @@
|
|||||||
{
|
{
|
||||||
key: 'love',
|
key: 'love',
|
||||||
title: '恋爱日记',
|
title: '恋爱日记',
|
||||||
bgColor: 'rgba(255, 76, 103, 0.95)',
|
color: '#FF4C67',
|
||||||
icon: 'heart',
|
bgGlass: 'rgba(255, 76, 103, 0.14)',
|
||||||
|
borderColor: 'rgba(255, 76, 103, 0.075)',
|
||||||
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-in-love',
|
||||||
path: '/pages-blog/love/love',
|
path: '/pages-blog/love/love',
|
||||||
// show: loveEnabled,
|
// show: loveEnabled,
|
||||||
show: true,
|
show: true,
|
||||||
@@ -53,8 +66,11 @@
|
|||||||
{
|
{
|
||||||
key: 'contact-blogger',
|
key: 'contact-blogger',
|
||||||
title: '联系博主',
|
title: '联系博主',
|
||||||
bgColor: 'rgba(255, 152, 0, 0.95)',
|
color: '#FF9800',
|
||||||
icon: 'message',
|
bgGlass: 'rgba(255, 152, 0, 0.14)',
|
||||||
|
borderColor: 'rgba(255, 152, 0, 0.35)',
|
||||||
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-cool',
|
||||||
path: '/pages-blog/contact/contact',
|
path: '/pages-blog/contact/contact',
|
||||||
show: socialEnabled,
|
show: socialEnabled,
|
||||||
},
|
},
|
||||||
@@ -68,21 +84,37 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view v-if="navList.length" class="overflow-hidden rounded-xl p-3 px-4 mb-3">
|
<view v-if="navList.length" class="box-border overflow-hidden rounded-xl p-3 px-4 mb-3">
|
||||||
<uh-section-title class="mb-4">
|
<uh-section-title class="mb-4">
|
||||||
快捷导航
|
快捷导航
|
||||||
</uh-section-title>
|
</uh-section-title>
|
||||||
<view class="grid grid-cols-5 gap-4">
|
<view class="grid grid-cols-5 gap-4">
|
||||||
<view v-for="item in navList" :key="item.key" class="flex flex-col items-center gap-2"
|
<view v-for="item in navList" :key="item.key" class="flex flex-col items-center gap-2"
|
||||||
@click="handleClickNav(item)">
|
@click="handleClickNav(item)">
|
||||||
<view class="uh-global-card-glass border h-12 w-12 flex items-center justify-center rounded-2xl"
|
<view
|
||||||
:style="{ backgroundColor: item.bgColor }">
|
class="uh-global-card-glass uh-shadow-xs h-13 w-13 flex items-center justify-center rounded-2xl border transition-transform active:scale-90"
|
||||||
<wd-icon :name="item.icon" size="24px" color="#fff" />
|
:style="{
|
||||||
|
backgroundColor: item.bgGlass
|
||||||
|
}">
|
||||||
|
<wd-icon :class-prefix="item.iconPrefix" :name="item.icon" size="64rpx" :color="item.color" />
|
||||||
</view>
|
</view>
|
||||||
<view class="text-xs text-gray-900 font-bold">
|
<view class="text-xs text-gray-900">
|
||||||
{{ item.title }}
|
{{ item.title }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</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>
|
||||||
@@ -6,12 +6,15 @@
|
|||||||
useBack : boolean;
|
useBack : boolean;
|
||||||
useTitle : boolean;
|
useTitle : boolean;
|
||||||
defaultTitle ?: string;
|
defaultTitle ?: string;
|
||||||
|
titleColor ?: string;
|
||||||
scrollTitle ?: string;
|
scrollTitle ?: string;
|
||||||
|
needPlaceholder ?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<IProps>(), {
|
const props = withDefaults(defineProps<IProps>(), {
|
||||||
useBack: true,
|
useBack: true,
|
||||||
useTitle: true,
|
useTitle: true,
|
||||||
|
needPlaceholder: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const slots = useSlots()
|
const slots = useSlots()
|
||||||
@@ -31,6 +34,10 @@
|
|||||||
|
|
||||||
const customCalss = computed(() => {
|
const customCalss = computed(() => {
|
||||||
const _class = []
|
const _class = []
|
||||||
|
if (props.titleColor) {
|
||||||
|
_class.push(props.titleColor)
|
||||||
|
return
|
||||||
|
}
|
||||||
if (scrollThreshold.value) {
|
if (scrollThreshold.value) {
|
||||||
_class.push('text-white')
|
_class.push('text-white')
|
||||||
}
|
}
|
||||||
@@ -61,6 +68,7 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<view class="w-full box-border">
|
||||||
<view class="box-border pt-safe w-full fixed left-0 top-0 z-50" :class="customCalss" :style="[customStyle]">
|
<view class="box-border pt-safe w-full fixed left-0 top-0 z-50" :class="customCalss" :style="[customStyle]">
|
||||||
<view class="w-full h-[46px] flex items-center gap-x-4 box-border px-3 backdrop-blur-[2rpx]">
|
<view class="w-full h-[46px] flex items-center gap-x-4 box-border px-3 backdrop-blur-[2rpx]">
|
||||||
<!-- 左边 -->
|
<!-- 左边 -->
|
||||||
@@ -82,4 +90,8 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
<view v-if="props.needPlaceholder" class="box-border w-full pt-safe">
|
||||||
|
<view class="w-full h-[46px]"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -81,9 +81,7 @@
|
|||||||
<!-- 头部:标题 + 关闭 -->
|
<!-- 头部:标题 + 关闭 -->
|
||||||
<view class="flex items-center justify-between">
|
<view class="flex items-center justify-between">
|
||||||
<view class="flex items-center gap-2">
|
<view class="flex items-center gap-2">
|
||||||
<text class="text-sm">
|
<wd-icon class-prefix="uhemoji2-icon" name="-happy-" size="36rpx" />
|
||||||
📢
|
|
||||||
</text>
|
|
||||||
<text class="text-md font-bold text-gray-900">
|
<text class="text-md font-bold text-gray-900">
|
||||||
最新公告
|
最新公告
|
||||||
</text>
|
</text>
|
||||||
@@ -101,7 +99,8 @@
|
|||||||
|
|
||||||
<!-- 内容 -->
|
<!-- 内容 -->
|
||||||
<view class="mt-4">
|
<view class="mt-4">
|
||||||
<image v-if="notice.cover" :src="checkImageUrl(notice.cover)" class="w-full h-34 rounded-lg mb-2"></image>
|
<image v-if="notice.cover" :src="checkImageUrl(notice.cover)" class="w-full h-34 rounded-lg mb-2">
|
||||||
|
</image>
|
||||||
<view class="text-md font-bold leading-snug text-gray-900">
|
<view class="text-md font-bold leading-snug text-gray-900">
|
||||||
{{ notice.title }}
|
{{ notice.title }}
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
/**
|
|
||||||
* 插件不可用提示(源自旧项目 components/plugin-unavailable,新建复刻)
|
|
||||||
* 当依赖的 Halo 插件未安装/未启用时展示:插件 logo、名称、错误标签、描述、插件地址、复制/反馈按钮
|
|
||||||
*/
|
|
||||||
import { computed } from 'vue'
|
import { computed } from 'vue'
|
||||||
import { NeedPlugins } from '@/hooks/usePluginAvailable'
|
import { NeedPlugins } from '@/hooks/usePluginAvailable'
|
||||||
|
|
||||||
@@ -46,17 +42,6 @@
|
|||||||
...props.customStyle,
|
...props.customStyle,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
function copy() {
|
|
||||||
if (!pluginInfo.value.url)
|
|
||||||
return
|
|
||||||
uni.setClipboardData({
|
|
||||||
data: pluginInfo.value.url,
|
|
||||||
showToast: false,
|
|
||||||
success: () => {
|
|
||||||
uni.showToast({ icon: 'none', title: '插件地址已复制' })
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 获取当前页面,并且设置黑名单模式,因为有的页面可能不需要滚动到顶部
|
// 获取当前页面,并且设置黑名单模式,因为有的页面可能不需要滚动到顶部
|
||||||
const balckList = ['pages/maintenance/maintenance']
|
const balckList = ['pages/maintenance/maintenance','pages-blog/setting/setting']
|
||||||
const pages = getCurrentPages()
|
const pages = getCurrentPages()
|
||||||
const currentPage = pages[pages.length - 1]
|
const currentPage = pages[pages.length - 1]
|
||||||
const visible = computed(() => {
|
const visible = computed(() => {
|
||||||
|
|||||||
@@ -461,12 +461,10 @@ const globalAppSettings = computed(() => settingStore.settings)
|
|||||||
<template>
|
<template>
|
||||||
<view class="box-border min-h-screen w-screen flex flex-col bg-page pb-safe">
|
<view class="box-border min-h-screen w-screen flex flex-col bg-page pb-safe">
|
||||||
<!-- 顶部导航 -->
|
<!-- 顶部导航 -->
|
||||||
<uh-navbar default-title="内容详情" :scroll-title="result?.spec?.title" />
|
<uh-navbar default-title="内容详情" :need-placeholder="false" :scroll-title="result?.spec?.title" />
|
||||||
|
|
||||||
<!-- 骨架屏 -->
|
<uh-data-loading v-if="loadingStatus !== 'success'" :loading-status="loadingStatus"
|
||||||
<view v-if="loadingStatus !== 'success'" class="box-border p-4">
|
@refresh="handleGetData()" />
|
||||||
<uh-data-loading :loading-status="loadingStatus" @refresh="handleGetData()" />
|
|
||||||
</view>
|
|
||||||
|
|
||||||
<view v-else class="box-border pt-72">
|
<view v-else class="box-border pt-72">
|
||||||
<!-- 顶部背景封面区域 -->
|
<!-- 顶部背景封面区域 -->
|
||||||
@@ -479,31 +477,26 @@ const globalAppSettings = computed(() => settingStore.settings)
|
|||||||
class="uh-global-card-glass box-border overflow-hidden border rounded-lt-3xl rounded-rt-3xl border-b-none -translate-y-12"
|
class="uh-global-card-glass box-border overflow-hidden border rounded-lt-3xl rounded-rt-3xl border-b-none -translate-y-12"
|
||||||
:style="{
|
:style="{
|
||||||
boxShadow: '0 -16rpx 12rpx rgba(0, 0, 0, 0.035)',
|
boxShadow: '0 -16rpx 12rpx rgba(0, 0, 0, 0.035)',
|
||||||
}"
|
}">
|
||||||
>
|
|
||||||
<!-- 顶部信息 -->
|
<!-- 顶部信息 -->
|
||||||
<view class="box-border flex flex-col gap-3 p-3 pb-2">
|
<view class="box-border flex flex-col gap-3 p-3 pb-2">
|
||||||
<view class="flex items-center gap-x-2">
|
<view class="flex items-center gap-x-2">
|
||||||
<image
|
<image :src="result.owner.avatar" class="uh-global-card-glass block h-6 w-6 rounded-full"
|
||||||
:src="result.owner.avatar" class="uh-global-card-glass block h-6 w-6 rounded-full"
|
mode="aspectFill" />
|
||||||
mode="aspectFill"
|
|
||||||
/>
|
|
||||||
<text class="text-sm font-semibold">{{ result?.owner?.displayName }}</text>
|
<text class="text-sm font-semibold">{{ result?.owner?.displayName }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="font-semibold">
|
<view class="font-semibold">
|
||||||
{{ result?.spec.title }}
|
{{ result?.spec.title }}
|
||||||
</view>
|
</view>
|
||||||
<view class="flex flex-wrap items-center gap-2 text-xs">
|
<view class="flex flex-wrap items-center gap-2 text-xs">
|
||||||
<text
|
<text v-for="(item, index) in result?.categories" :key="index"
|
||||||
v-for="(item, index) in result?.categories" :key="index"
|
class="uh-global-card-glass uh-shadow-xs border rounded-full px-2 py-1"
|
||||||
class="uh-global-card-glass uh-shadow-xs border rounded-full px-2 py-1" @click="handleToCate(item)"
|
@click="handleToCate(item)">
|
||||||
>
|
|
||||||
{{ item.spec.displayName }}
|
{{ item.spec.displayName }}
|
||||||
</text>
|
</text>
|
||||||
<text
|
<text v-for="(item, index) in result?.tags" :key="index"
|
||||||
v-for="(item, index) in result?.tags" :key="index"
|
class="uh-global-card-glass uh-shadow-xs border rounded-full px-2 py-1"
|
||||||
class="uh-global-card-glass uh-shadow-xs border rounded-full px-2 py-1" @click="handleToTag(item)"
|
@click="handleToTag(item)">
|
||||||
>
|
|
||||||
#{{ item.spec.displayName }}
|
#{{ item.spec.displayName }}
|
||||||
</text>
|
</text>
|
||||||
</view>
|
</view>
|
||||||
@@ -545,39 +538,31 @@ const globalAppSettings = computed(() => settingStore.settings)
|
|||||||
<!-- 受限阅读 -->
|
<!-- 受限阅读 -->
|
||||||
<template v-if="checkPostRestrictRead(result!)">
|
<template v-if="checkPostRestrictRead(result!)">
|
||||||
<view v-if="showContentArr.length === 0">
|
<view v-if="showContentArr.length === 0">
|
||||||
<uh-restrict-read-skeleton
|
<uh-restrict-read-skeleton :loading="true" :lines="3"
|
||||||
:loading="true" :lines="3"
|
|
||||||
:tip-text="`此处内容已隐藏,「${getRestrictReadTypeName(result!)}可见」`"
|
:tip-text="`此处内容已隐藏,「${getRestrictReadTypeName(result!)}可见」`"
|
||||||
:button-text="getRestrictReadTypeName(result!)" button-color="#1890ff"
|
:button-text="getRestrictReadTypeName(result!)" button-color="#1890ff"
|
||||||
@refresh="readMore"
|
@refresh="readMore" />
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
<view v-for="(showContent, showContentIndex) in showContentArr" v-else :key="showContentIndex">
|
<view v-for="(showContent, showContentIndex) in showContentArr" v-else :key="showContentIndex">
|
||||||
<mp-html
|
<mp-html lazy-load :domain="markdownConfig.domain ?? ''"
|
||||||
lazy-load :domain="markdownConfig.domain ?? ''"
|
|
||||||
:loading-img="markdownConfig.loadingGif" scroll-table selectable
|
:loading-img="markdownConfig.loadingGif" scroll-table selectable
|
||||||
:tag-style="markdownConfig.tagStyle" :container-style="markdownConfig.containStyle"
|
:tag-style="markdownConfig.tagStyle" :container-style="markdownConfig.containStyle"
|
||||||
:content="showContent" :markdown="true" :show-line-number="true"
|
:content="showContent" :markdown="true" :show-line-number="true"
|
||||||
:show-language-name="true" copy-by-long-press
|
:show-language-name="true" copy-by-long-press />
|
||||||
/>
|
<uh-restrict-read-skeleton :loading="true" :lines="3"
|
||||||
<uh-restrict-read-skeleton
|
|
||||||
:loading="true" :lines="3"
|
|
||||||
:tip-text="`此处内容已隐藏,「${getRestrictReadTypeName(result!)}可见」`"
|
:tip-text="`此处内容已隐藏,「${getRestrictReadTypeName(result!)}可见」`"
|
||||||
:button-text="getRestrictReadTypeName(result!)" button-color="#1890ff"
|
:button-text="getRestrictReadTypeName(result!)" button-color="#1890ff"
|
||||||
@refresh="readMore"
|
@refresh="readMore" />
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 正常渲染 -->
|
<!-- 正常渲染 -->
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<mp-html
|
<mp-html lazy-load :domain="markdownConfig.domain ?? ''"
|
||||||
lazy-load :domain="markdownConfig.domain ?? ''"
|
|
||||||
:loading-img="markdownConfig.loadingGif" scroll-table selectable
|
:loading-img="markdownConfig.loadingGif" scroll-table selectable
|
||||||
:tag-style="markdownConfig.tagStyle" :container-style="markdownConfig.containStyle"
|
:tag-style="markdownConfig.tagStyle" :container-style="markdownConfig.containStyle"
|
||||||
:content="result?.content?.raw || ''" :markdown="true" :show-line-number="true"
|
:content="result?.content?.raw || ''" :markdown="true" :show-line-number="true"
|
||||||
:show-language-name="true" copy-by-long-press
|
:show-language-name="true" copy-by-long-press />
|
||||||
/>
|
|
||||||
</template>
|
</template>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -601,11 +586,9 @@ const globalAppSettings = computed(() => settingStore.settings)
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 评论区域 -->
|
<!-- 评论区域 -->
|
||||||
<uh-comment-list
|
<uh-comment-list v-if="calcIsShowComment && result" :disallow-comment="!result.spec.allowComment"
|
||||||
v-if="calcIsShowComment && result" :disallow-comment="!result.spec.allowComment"
|
|
||||||
:post-name="result.metadata.name" :post="result" @on-comment="handleOnComment"
|
:post-name="result.metadata.name" :post="result" @on-comment="handleOnComment"
|
||||||
@on-comment-detail="handleOnShowCommentDetail"
|
@on-comment-detail="handleOnShowCommentDetail" />
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@@ -613,27 +596,22 @@ const globalAppSettings = computed(() => settingStore.settings)
|
|||||||
<view class="fixed bottom-8 left-1/2 z-10 flex items-center justify-center pb-safe -translate-x-1/2">
|
<view class="fixed bottom-8 left-1/2 z-10 flex items-center justify-center pb-safe -translate-x-1/2">
|
||||||
<!-- #7BE200 -->
|
<!-- #7BE200 -->
|
||||||
<view
|
<view
|
||||||
class="uh-global-card-glass box-border flex items-center justify-center gap-2 border rounded-full p-1 text-primary"
|
class="uh-global-card-glass box-border flex items-center justify-center gap-2 border rounded-full p-1 text-primary">
|
||||||
>
|
|
||||||
<view
|
<view
|
||||||
class="uh-global-card-glass box-border h-[72rpx] flex flex-1 items-center justify-center gap-x-1 border rounded-full px-4 shadow-none"
|
class="uh-global-card-glass box-border h-[72rpx] flex flex-1 items-center justify-center gap-x-1 border rounded-full px-4 shadow-none"
|
||||||
:class="{ active: hasUpvoted() }" @click="handleDoLikes"
|
:class="{ active: hasUpvoted() }" @click="handleDoLikes">
|
||||||
>
|
|
||||||
<wd-icon class-prefix="uhemoji-icon" name="-kiss-" size="36rpx" />
|
<wd-icon class-prefix="uhemoji-icon" name="-kiss-" size="36rpx" />
|
||||||
<text class="shrink-0 text-sm text-gray-900 font-semibold">点赞</text>
|
<text class="shrink-0 text-sm text-gray-900 font-semibold">点赞</text>
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view v-if="calcIsShowComment"
|
||||||
v-if="calcIsShowComment"
|
|
||||||
class="uh-global-card-glass box-border h-[72rpx] flex flex-1 items-center justify-center gap-x-1 border rounded-full px-4 shadow-none"
|
class="uh-global-card-glass box-border h-[72rpx] flex flex-1 items-center justify-center gap-x-1 border rounded-full px-4 shadow-none"
|
||||||
@click="handleToComment()"
|
@click="handleToComment()">
|
||||||
>
|
|
||||||
<wd-icon class-prefix="uhemoji-icon" name="-thinking" size="36rpx" />
|
<wd-icon class-prefix="uhemoji-icon" name="-thinking" size="36rpx" />
|
||||||
<text class="shrink-0 text-sm text-gray-900 font-semibold">评论</text>
|
<text class="shrink-0 text-sm text-gray-900 font-semibold">评论</text>
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
class="uh-global-card-glass box-border h-[72rpx] flex flex-1 items-center justify-center gap-x-1 border rounded-full px-4 shadow-none"
|
class="uh-global-card-glass box-border h-[72rpx] flex flex-1 items-center justify-center gap-x-1 border rounded-full px-4 shadow-none"
|
||||||
@click="handleTogglePostFavorite"
|
@click="handleTogglePostFavorite">
|
||||||
>
|
|
||||||
<wd-icon class-prefix="uhemoji-icon" name="-smile-" size="36rpx" />
|
<wd-icon class-prefix="uhemoji-icon" name="-smile-" size="36rpx" />
|
||||||
<text class="shrink-0 text-sm text-gray-900 font-semibold"
|
<text class="shrink-0 text-sm text-gray-900 font-semibold"
|
||||||
:style="hasFavorited() ? { color: '#ffb300' } : ''">{{ hasFavorited() ? '已收藏' : '收藏' }}</text>
|
:style="hasFavorited() ? { color: '#ffb300' } : ''">{{ hasFavorited() ? '已收藏' : '收藏' }}</text>
|
||||||
@@ -643,33 +621,25 @@ const globalAppSettings = computed(() => settingStore.settings)
|
|||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 密码弹窗 -->
|
<!-- 密码弹窗 -->
|
||||||
<wd-dialog
|
<wd-dialog v-model="passwordModal.show" title="验证提示" :show-cancel="true" show-confirm-button confirm-text="确定"
|
||||||
v-model="passwordModal.show" title="验证提示" :show-cancel="true" show-confirm-button confirm-text="确定"
|
@confirm="restrictReadCheck">
|
||||||
@confirm="restrictReadCheck"
|
|
||||||
>
|
|
||||||
<view class="modal-body py-4">
|
<view class="modal-body py-4">
|
||||||
<wd-input v-model="restrictReadInputCode" placeholder="请输入密码" />
|
<wd-input v-model="restrictReadInputCode" placeholder="请输入密码" />
|
||||||
</view>
|
</view>
|
||||||
</wd-dialog>
|
</wd-dialog>
|
||||||
|
|
||||||
<!-- 验证码弹窗 -->
|
<!-- 验证码弹窗 -->
|
||||||
<wd-dialog
|
<wd-dialog v-model="verificationCodeModal.show" title="验证提示" :show-cancel="true" confirm-text="确定"
|
||||||
v-model="verificationCodeModal.show" title="验证提示" :show-cancel="true" confirm-text="确定"
|
@confirm="restrictReadCheck">
|
||||||
@confirm="restrictReadCheck"
|
|
||||||
>
|
|
||||||
<view class="modal-body py-4">
|
<view class="modal-body py-4">
|
||||||
<image
|
<image v-if="verificationCodeModal.imgUrl" :src="verificationCodeModal.imgUrl"
|
||||||
v-if="verificationCodeModal.imgUrl" :src="verificationCodeModal.imgUrl"
|
class="modal-code-img mb-4 h-[200rpx] w-full" mode="aspectFit" />
|
||||||
class="modal-code-img mb-4 h-[200rpx] w-full" mode="aspectFit"
|
|
||||||
/>
|
|
||||||
<wd-input v-model="restrictReadInputCode" placeholder="请输入验证码" class="mt-2" />
|
<wd-input v-model="restrictReadInputCode" placeholder="请输入验证码" class="mt-2" />
|
||||||
</view>
|
</view>
|
||||||
</wd-dialog>
|
</wd-dialog>
|
||||||
|
|
||||||
<!-- 评论弹窗 -->
|
<!-- 评论弹窗 -->
|
||||||
<uh-comment-modal
|
<uh-comment-modal v-if="commentModal.show" :show="commentModal.show" :is-comment="commentModal.isComment"
|
||||||
v-if="commentModal.show" :show="commentModal.show" :is-comment="commentModal.isComment"
|
:title="commentModal.title" :post-name="commentModal.postName" @on-close="handleOnCommentModalClose" />
|
||||||
:title="commentModal.title" :post-name="commentModal.postName" @on-close="handleOnCommentModalClose"
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,10 +1,4 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
/**
|
|
||||||
* 收藏页(纯本地,文章 × 瞬间)
|
|
||||||
* 功能:双 Tab(仿图库顶部吸顶胶囊 chip)本地收藏列表 + 跳详情 + 删除 + 状态舞台
|
|
||||||
* 数据:useFavoritesStore(persist),快照自包含,无需网络加载
|
|
||||||
* 状态:useDataLoadingStatus + uh-data-loading(与 tabbar 页同构);本地同步数据,状态直接推导
|
|
||||||
*/
|
|
||||||
import { computed, ref, watchEffect } from 'vue'
|
import { computed, ref, watchEffect } from 'vue'
|
||||||
import { formatTime } from '@/utils/formatTime'
|
import { formatTime } from '@/utils/formatTime'
|
||||||
import { useFavoritesStore } from '@/store/favorites'
|
import { useFavoritesStore } from '@/store/favorites'
|
||||||
@@ -14,7 +8,7 @@ import type { FavoriteKind, IFavoriteItem } from '@/utils/favorite'
|
|||||||
definePage({
|
definePage({
|
||||||
style: {
|
style: {
|
||||||
navigationBarTitleText: '我的收藏',
|
navigationBarTitleText: '我的收藏',
|
||||||
backgroundColor: '#f6f3ee',
|
navigationStyle: 'custom',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -80,6 +74,9 @@ const emptyText = computed(() => (activeKind.value === 'post' ? '还没有收藏
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="box-border min-h-screen w-screen bg-page pb-10">
|
<view class="box-border min-h-screen w-screen bg-page pb-10">
|
||||||
|
<!-- 自定义导航 -->
|
||||||
|
<uh-navbar default-title="我的收藏" title-color="text-gray-900"></uh-navbar>
|
||||||
|
|
||||||
<!-- 顶部类型 Tab(与图库页同款:吸顶玻璃胶囊 chip) -->
|
<!-- 顶部类型 Tab(与图库页同款:吸顶玻璃胶囊 chip) -->
|
||||||
<wd-sticky>
|
<wd-sticky>
|
||||||
<scroll-view scroll-x class="w-full whitespace-nowrap">
|
<scroll-view scroll-x class="w-full whitespace-nowrap">
|
||||||
|
|||||||
@@ -1,10 +1,4 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
/**
|
|
||||||
* 偏好设置页(两层:站点默认 L0 + 本地差异 L1-L,设计见 .docs/config-system-v2-redesign §3-4)
|
|
||||||
* - 每项可「跟随站点默认」(差异为空)或覆盖为具体值;改动即写本地差异(uh_pref_local_v1)即时生效;
|
|
||||||
* - 底部「重置为站点默认」= 清空全部本地差异,回退站长在插件后台配置的默认(未配置则为内置默认)。
|
|
||||||
* - 风格:对齐全站设计语言(bg-page + uh-global-card-glass + uh-section-title)
|
|
||||||
*/
|
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { onLoad } from '@dcloudio/uni-app'
|
import { onLoad } from '@dcloudio/uni-app'
|
||||||
import { DefaultAppSettings } from '@/config/appSettings'
|
import { DefaultAppSettings } from '@/config/appSettings'
|
||||||
@@ -16,6 +10,7 @@ import type { LocalPrefs } from '@/utils/preference'
|
|||||||
definePage({
|
definePage({
|
||||||
style: {
|
style: {
|
||||||
navigationBarTitleText: '偏好设置',
|
navigationBarTitleText: '偏好设置',
|
||||||
|
navigationStyle: 'custom'
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -88,24 +83,7 @@ const layoutPrefs: PrefDef[] = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const featurePrefs : PrefDef[] = [
|
const featurePrefs : PrefDef[] = [
|
||||||
{ key: 'useWaterfull', label: '图库瀑布流模式', kind: 'bool', path: ['gallery', 'useWaterfull'] },
|
|
||||||
{ key: 'useSimple', label: '友链简洁模式', kind: 'bool', path: ['links', 'useSimple'] },
|
|
||||||
{ key: 'isAvatarRadius', label: '是否圆形头像', kind: 'bool', path: ['isAvatarRadius'] },
|
{ key: 'isAvatarRadius', label: '是否圆形头像', kind: 'bool', path: ['isAvatarRadius'] },
|
||||||
{ key: 'useDot', label: '轮播图指示器', kind: 'bool', path: ['banner', 'useDot'] },
|
|
||||||
{
|
|
||||||
key: 'dotPosition',
|
|
||||||
label: '指示器位置',
|
|
||||||
kind: 'enum',
|
|
||||||
path: ['banner', 'dotPosition'],
|
|
||||||
options: [
|
|
||||||
{ label: '右边', value: 'right' },
|
|
||||||
{ label: '下边', value: 'bottom' },
|
|
||||||
],
|
|
||||||
siteLabelOf: (value: string) => {
|
|
||||||
const map: Record<string, string> = { right: '右边', bottom: '下边', left: '左边', top: '上边' }
|
|
||||||
return map[value] || value
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
/* ---------------- 状态读取 ---------------- */
|
/* ---------------- 状态读取 ---------------- */
|
||||||
@@ -205,143 +183,125 @@ function handleResetAll() {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="app-page box-border min-h-screen bg-page pb-[200rpx]">
|
<view class="box-border min-h-screen bg-page">
|
||||||
<!-- 说明 -->
|
<!-- 自定义标题 -->
|
||||||
<view class="pref-tip uh-global-card-glass mx-4 mt-4 flex items-start gap-2 rounded-xl px-4 py-3">
|
<uh-navbar default-title="偏好设置" title-color="text-gray-900" :need-placeholder="true"></uh-navbar>
|
||||||
<wd-icon name="info" size="28rpx" color="#a8a294" class="mt-0.5 shrink-0" />
|
|
||||||
<text class="tip-text flex-1 text-2xs text-gray-400 leading-[1.6]">
|
|
||||||
你的偏好仅保存在本机。未自定义的项自动跟随站长在插件后台配置的「站点默认」;点击底部「重置为站点默认」可清空全部本地偏好。
|
|
||||||
</text>
|
|
||||||
</view>
|
|
||||||
|
|
||||||
|
<!-- 内容区域 -->
|
||||||
|
<view class="box-border p-3 flex flex-col gap-y-6">
|
||||||
<!-- 布局设置 -->
|
<!-- 布局设置 -->
|
||||||
<uh-section-title class="mx-4 mb-3 mt-6 text-[30rpx]">
|
<view class="flex flex-col gap-y-3">
|
||||||
|
<uh-section-title>
|
||||||
布局
|
布局
|
||||||
<template #right>
|
<template #right>
|
||||||
<text class="text-2xs text-gray-400">应用以及文章列表布局设置</text>
|
<text class="text-2xs text-gray-400">应用以及文章列表布局设置</text>
|
||||||
</template>
|
</template>
|
||||||
</uh-section-title>
|
</uh-section-title>
|
||||||
<view class="setting-sheet uh-global-card-glass mx-4 overflow-hidden rounded-2xl">
|
<view class="uh-global-card-glass overflow-hidden rounded-2xl">
|
||||||
<view
|
<view v-for="(def, index) in layoutPrefs" :key="def.key"
|
||||||
v-for="(def, index) in layoutPrefs"
|
|
||||||
:key="def.key"
|
|
||||||
class="pick-row flex items-center justify-between px-4 py-4"
|
class="pick-row flex items-center justify-between px-4 py-4"
|
||||||
:class="index < layoutPrefs.length - 1 ? 'border-b border-black/5' : ''"
|
:class="index < layoutPrefs.length - 1 ? 'border-b border-black/5' : ''"
|
||||||
@click="handleOpenEnum(def)"
|
@click="handleOpenEnum(def)">
|
||||||
>
|
|
||||||
<view class="row-left flex flex-col gap-1">
|
<view class="row-left flex flex-col gap-1">
|
||||||
<text class="row-label text-[28rpx] text-gray-900 font-bold">{{ def.label }}</text>
|
<text class="row-label text-[28rpx] text-gray-900 font-bold">{{ def.label }}</text>
|
||||||
<view class="flex items-center gap-2">
|
<view class="flex items-center gap-2">
|
||||||
<text v-if="isFollowing(def)" class="row-sub text-2xs text-gray-400">跟随站点默认</text>
|
<text v-if="isFollowing(def)" class="row-sub text-2xs text-gray-400">跟随站点默认</text>
|
||||||
<view v-else class="rounded-full bg-secondary px-2 py-0.5 text-[20rpx] text-[#4d7c0f] leading-none">
|
<view v-else
|
||||||
|
class="rounded-full bg-secondary px-2 py-0.5 text-[20rpx] text-[#4d7c0f] leading-none">
|
||||||
已自定义
|
已自定义
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="row-value flex items-center gap-2">
|
<view class="row-value flex items-center gap-2">
|
||||||
<text class="value-text text-[26rpx] text-gray-400">{{ enumLabelOf(def, valueOf(def.path)) }}</text>
|
<text
|
||||||
|
class="value-text text-[26rpx] text-gray-400">{{ enumLabelOf(def, valueOf(def.path)) }}</text>
|
||||||
<wd-icon name="arrow-right" size="12px" color="#c8c2b4" />
|
<wd-icon name="arrow-right" size="12px" color="#c8c2b4" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
<!-- 功能设置 -->
|
<!-- 功能设置 -->
|
||||||
<uh-section-title class="mx-4 mb-3 mt-6 text-[30rpx]">
|
<view class="flex flex-col gap-y-3">
|
||||||
|
<uh-section-title>
|
||||||
功能
|
功能
|
||||||
<template #right>
|
<template #right>
|
||||||
<text class="text-2xs text-gray-400">一些常用的功能性设置</text>
|
<text class="text-2xs text-gray-400">一些常用的功能性设置</text>
|
||||||
</template>
|
</template>
|
||||||
</uh-section-title>
|
</uh-section-title>
|
||||||
<view class="setting-sheet uh-global-card-glass mx-4 overflow-hidden rounded-2xl">
|
<view class="setting-sheet uh-global-card-glass overflow-hidden rounded-2xl">
|
||||||
<template v-for="(def, index) in featurePrefs" :key="def.key">
|
<template v-for="(def, index) in featurePrefs" :key="def.key">
|
||||||
<!-- 布尔开关 -->
|
<!-- 布尔开关 -->
|
||||||
<view
|
<view v-if="def.kind === 'bool'" class="switch-row flex items-center justify-between px-4 py-4"
|
||||||
v-if="def.kind === 'bool'"
|
:class="index < featurePrefs.length - 1 ? 'border-b border-black/5' : ''">
|
||||||
class="switch-row flex items-center justify-between px-4 py-4"
|
|
||||||
:class="index < featurePrefs.length - 1 ? 'border-b border-black/5' : ''"
|
|
||||||
>
|
|
||||||
<view class="row-left flex flex-col gap-1">
|
<view class="row-left flex flex-col gap-1">
|
||||||
<text class="row-label text-[28rpx] text-gray-900 font-bold">{{ def.label }}</text>
|
<text class="row-label text-[28rpx] text-gray-900 font-bold">{{ def.label }}</text>
|
||||||
<view class="flex items-center gap-2">
|
<view class="flex items-center gap-2">
|
||||||
<text v-if="isFollowing(def)" class="row-sub text-2xs text-gray-400">跟随站点默认</text>
|
<text v-if="isFollowing(def)" class="row-sub text-2xs text-gray-400">跟随站点默认</text>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<view class="rounded-full bg-secondary px-2 py-0.5 text-[20rpx] text-[#4d7c0f] leading-none">
|
<view
|
||||||
|
class="rounded-full bg-secondary px-2 py-0.5 text-[20rpx] text-[#4d7c0f] leading-none">
|
||||||
已自定义
|
已自定义
|
||||||
</view>
|
</view>
|
||||||
<text class="revert-text text-2xs text-gray-400 underline" @click.stop="handleRevert(def.path)">恢复默认</text>
|
<text class="revert-text text-2xs text-gray-400 underline"
|
||||||
|
@click.stop="handleRevert(def.path)">恢复默认</text>
|
||||||
</template>
|
</template>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<wd-switch :model-value="!!valueOf(def.path)" @change="handleSwitchChange(def, $event)" />
|
<wd-switch :model-value="def.path" @change="handleSwitchChange(def, $event)" />
|
||||||
</view>
|
</view>
|
||||||
<!-- 枚举选择(指示器位置) -->
|
<!-- 枚举选择(指示器位置) -->
|
||||||
<view
|
<view v-else class="pick-row flex items-center justify-between px-4 py-4"
|
||||||
v-else
|
|
||||||
class="pick-row flex items-center justify-between px-4 py-4"
|
|
||||||
:class="index < featurePrefs.length - 1 ? 'border-b border-black/5' : ''"
|
:class="index < featurePrefs.length - 1 ? 'border-b border-black/5' : ''"
|
||||||
@click="handleOpenEnum(def)"
|
@click="handleOpenEnum(def)">
|
||||||
>
|
|
||||||
<view class="row-left flex flex-col gap-1">
|
<view class="row-left flex flex-col gap-1">
|
||||||
<text class="row-label text-[28rpx] text-gray-900 font-bold">{{ def.label }}</text>
|
<text class="row-label text-[28rpx] text-gray-900 font-bold">{{ def.label }}</text>
|
||||||
<view class="flex items-center gap-2">
|
<view class="flex items-center gap-2">
|
||||||
<text v-if="isFollowing(def)" class="row-sub text-2xs text-gray-400">跟随站点默认</text>
|
<text v-if="isFollowing(def)" class="row-sub text-2xs text-gray-400">跟随站点默认</text>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<view class="rounded-full bg-secondary px-2 py-0.5 text-[20rpx] text-[#4d7c0f] leading-none">
|
<view
|
||||||
|
class="rounded-full bg-secondary px-2 py-0.5 text-[20rpx] text-[#4d7c0f] leading-none">
|
||||||
已自定义
|
已自定义
|
||||||
</view>
|
</view>
|
||||||
<text class="revert-text text-2xs text-gray-400 underline" @click.stop="handleRevert(def.path)">恢复默认</text>
|
<text class="revert-text text-2xs text-gray-400 underline"
|
||||||
|
@click.stop="handleRevert(def.path)">恢复默认</text>
|
||||||
</template>
|
</template>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<view class="row-value flex items-center gap-2">
|
<view class="row-value flex items-center gap-2">
|
||||||
<text class="value-text text-[26rpx] text-gray-400">{{ enumLabelOf(def, valueOf(def.path)) }}</text>
|
<text
|
||||||
|
class="value-text text-[26rpx] text-gray-400">{{ enumLabelOf(def, valueOf(def.path)) }}</text>
|
||||||
<wd-icon name="arrow-right" size="12px" color="#c8c2b4" />
|
<wd-icon name="arrow-right" size="12px" color="#c8c2b4" />
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</view>
|
</view>
|
||||||
|
</view>
|
||||||
<!-- 底部操作栏(玻璃悬浮 + 底部安全区适配) -->
|
<!-- 底部操作栏(玻璃悬浮-->
|
||||||
<view class="btn-bar uh-global-card-glass fixed bottom-0 left-0 box-border w-screen px-4 pt-3 pb-safe">
|
<view class="box-border w-full px-2">
|
||||||
<view class="reset-btn h-[84rpx] w-full flex items-center justify-center rounded-full bg-gray-900 active:opacity-80" @click="handleResetAll">
|
<uh-button custom-class="uh-global-card-glass py-2 !rounded-full"
|
||||||
<text class="text-[28rpx] text-white font-bold">重置为站点默认</text>
|
@click="handleResetAll">恢复默认</uh-button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 枚举选择底部弹层 -->
|
<!-- 枚举选择底部弹层 -->
|
||||||
<wd-popup
|
<wd-popup v-model="enumSheet.show" position="bottom" closable custom-style="border-radius: 24rpx 24rpx 0 0;"
|
||||||
v-model="enumSheet.show"
|
@close="handleCloseEnum">
|
||||||
position="bottom"
|
|
||||||
closable
|
|
||||||
custom-style="border-radius: 24rpx 24rpx 0 0;"
|
|
||||||
@close="handleCloseEnum"
|
|
||||||
>
|
|
||||||
<view v-if="enumSheet.def" class="enum-sheet box-border w-full pb-[env(safe-area-inset-bottom)]">
|
<view v-if="enumSheet.def" class="enum-sheet box-border w-full pb-[env(safe-area-inset-bottom)]">
|
||||||
<view class="enum-title py-6 text-center text-[30rpx] text-gray-900 font-bold">
|
<view class="enum-title py-6 text-center text-[30rpx] text-gray-900 font-bold">
|
||||||
{{ enumSheet.def.label }}
|
{{ enumSheet.def.label }}
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view class="enum-item flex items-center justify-between px-6 py-5"
|
||||||
class="enum-item flex items-center justify-between px-6 py-5"
|
|
||||||
:class="isFollowing(enumSheet.def) ? 'bg-secondary text-[#4d7c0f]' : 'text-gray-900'"
|
:class="isFollowing(enumSheet.def) ? 'bg-secondary text-[#4d7c0f]' : 'text-gray-900'"
|
||||||
@click="handleChooseEnum(null)"
|
@click="handleChooseEnum(null)">
|
||||||
>
|
|
||||||
<text class="text-[28rpx]">跟随站点默认</text>
|
<text class="text-[28rpx]">跟随站点默认</text>
|
||||||
<wd-icon v-if="isFollowing(enumSheet.def)" name="check" size="16px" color="#4d7c0f" />
|
<wd-icon v-if="isFollowing(enumSheet.def)" name="check" size="16px" color="#4d7c0f" />
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view v-for="opt in enumSheet.def.options" :key="opt.value"
|
||||||
v-for="opt in enumSheet.def.options"
|
|
||||||
:key="opt.value"
|
|
||||||
class="enum-item flex items-center justify-between border-t border-[#f0ece2] px-6 py-5"
|
class="enum-item flex items-center justify-between border-t border-[#f0ece2] px-6 py-5"
|
||||||
:class="valueOf(enumSheet.def.path) === opt.value && !isFollowing(enumSheet.def) ? 'bg-secondary text-[#4d7c0f]' : 'text-gray-900'"
|
:class="valueOf(enumSheet.def.path) === opt.value && !isFollowing(enumSheet.def) ? 'bg-secondary text-[#4d7c0f]' : 'text-gray-900'"
|
||||||
@click="handleChooseEnum(opt.value)"
|
@click="handleChooseEnum(opt.value)">
|
||||||
>
|
|
||||||
<text class="text-[28rpx]">{{ opt.label }}</text>
|
<text class="text-[28rpx]">{{ opt.label }}</text>
|
||||||
<wd-icon
|
<wd-icon v-if="valueOf(enumSheet.def.path) === opt.value && !isFollowing(enumSheet.def)"
|
||||||
v-if="valueOf(enumSheet.def.path) === opt.value && !isFollowing(enumSheet.def)"
|
name="check" size="16px" color="#4d7c0f" />
|
||||||
name="check"
|
|
||||||
size="16px"
|
|
||||||
color="#4d7c0f"
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</wd-popup>
|
</wd-popup>
|
||||||
|
|||||||
@@ -1,14 +1,33 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { DataLoadingStatusEnum } from '@/hooks/useDataLoadingStatus'
|
import { DataLoadingStatusEnum, useDataLoadingStatus } from '@/hooks/useDataLoadingStatus'
|
||||||
|
|
||||||
definePage({
|
definePage({
|
||||||
style: {
|
style: {
|
||||||
navigationBarTitleText: '测试页面',
|
navigationBarTitleText: '测试页面',
|
||||||
|
navigationStyle: 'custom',
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
const { loadingStatus, updateLoadingStatus } = useDataLoadingStatus()
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
updateLoadingStatus(DataLoadingStatusEnum.Success)
|
||||||
|
}, 3000)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<view class="w-full h-screen">
|
<view class="w-full min-h-screen bg-page">
|
||||||
<uh-data-loading :loading-status="DataLoadingStatusEnum.Loading"></uh-data-loading>
|
<uh-navbar default-title="测试页面" :need-placeholder="true" title-color="text-gray-900"></uh-navbar>
|
||||||
|
|
||||||
|
<!-- 内容区:由于 uh-navbar 内置有占位,所以我们的页面的主要内容应该从这里开始,比如这里就可以设置内边距或者其他样式,最外层的 <view class="w-full min-h-screen bg-page"> 仅作为容器-->
|
||||||
|
<view class="box-border px-3">
|
||||||
|
<!-- 加载状态 -->
|
||||||
|
<uh-data-loading v-if="loadingStatus!==DataLoadingStatusEnum.Success" :loading-status="loadingStatus"
|
||||||
|
min-height="80vh"></uh-data-loading>
|
||||||
|
|
||||||
|
<!-- 实际内容 -->
|
||||||
|
<view v-else>
|
||||||
|
请求成功啦
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@@ -82,6 +82,7 @@ const allStats = computed(() => [
|
|||||||
interface INavItem {
|
interface INavItem {
|
||||||
key : string
|
key : string
|
||||||
title : string
|
title : string
|
||||||
|
iconPrefix ?: string
|
||||||
icon : string
|
icon : string
|
||||||
/** 图标块背景色(与首页快捷导航同色板,同一功能同色) */
|
/** 图标块背景色(与首页快捷导航同色板,同一功能同色) */
|
||||||
bgColor : string
|
bgColor : string
|
||||||
@@ -134,7 +135,8 @@ async function handleGetNavList() {
|
|||||||
{
|
{
|
||||||
key: 'favorites',
|
key: 'favorites',
|
||||||
title: '我的收藏',
|
title: '我的收藏',
|
||||||
icon: 'star',
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-smiling',
|
||||||
bgColor: 'rgba(255, 179, 0, 0.95)',
|
bgColor: 'rgba(255, 179, 0, 0.95)',
|
||||||
rightText: '',
|
rightText: '',
|
||||||
path: '/pages-blog/favorites/favorites',
|
path: '/pages-blog/favorites/favorites',
|
||||||
@@ -144,7 +146,8 @@ async function handleGetNavList() {
|
|||||||
{
|
{
|
||||||
key: 'data-visual',
|
key: 'data-visual',
|
||||||
title: '数据看板',
|
title: '数据看板',
|
||||||
icon: 'chart',
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-surprised',
|
||||||
bgColor: 'rgba(102, 60, 201, 0.95)',
|
bgColor: 'rgba(102, 60, 201, 0.95)',
|
||||||
rightText: '站点数据可视化',
|
rightText: '站点数据可视化',
|
||||||
path: '/pages-blog/data-visual/data-visual',
|
path: '/pages-blog/data-visual/data-visual',
|
||||||
@@ -154,7 +157,8 @@ async function handleGetNavList() {
|
|||||||
{
|
{
|
||||||
key: 'archives',
|
key: 'archives',
|
||||||
title: calcAuditModeEnabled.value ? '内容归档' : '文章归档',
|
title: calcAuditModeEnabled.value ? '内容归档' : '文章归档',
|
||||||
icon: 'folder',
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-mask',
|
||||||
bgColor: 'rgba(3, 169, 244, 0.95)',
|
bgColor: 'rgba(3, 169, 244, 0.95)',
|
||||||
rightText: calcAuditModeEnabled.value ? '全部已归档内容' : '全部已归档文章',
|
rightText: calcAuditModeEnabled.value ? '全部已归档内容' : '全部已归档文章',
|
||||||
path: '/pages-blog/archives/archives',
|
path: '/pages-blog/archives/archives',
|
||||||
@@ -164,7 +168,8 @@ async function handleGetNavList() {
|
|||||||
{
|
{
|
||||||
key: 'love',
|
key: 'love',
|
||||||
title: '恋爱日记',
|
title: '恋爱日记',
|
||||||
icon: 'heart',
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-in-love',
|
||||||
bgColor: 'rgba(255, 76, 103, 0.95)',
|
bgColor: 'rgba(255, 76, 103, 0.95)',
|
||||||
rightText: '博主的恋爱日记',
|
rightText: '博主的恋爱日记',
|
||||||
path: '/pages-blog/love/love',
|
path: '/pages-blog/love/love',
|
||||||
@@ -175,7 +180,8 @@ async function handleGetNavList() {
|
|||||||
{
|
{
|
||||||
key: 'vote',
|
key: 'vote',
|
||||||
title: '投票中心',
|
title: '投票中心',
|
||||||
icon: 'box',
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-confused',
|
||||||
bgColor: 'rgba(0, 188, 212, 0.95)',
|
bgColor: 'rgba(0, 188, 212, 0.95)',
|
||||||
rightText: '查看和进行投票',
|
rightText: '查看和进行投票',
|
||||||
path: '/pages-blog/votes/votes',
|
path: '/pages-blog/votes/votes',
|
||||||
@@ -186,7 +192,8 @@ async function handleGetNavList() {
|
|||||||
{
|
{
|
||||||
key: 'friend-links',
|
key: 'friend-links',
|
||||||
title: '友情链接',
|
title: '友情链接',
|
||||||
icon: 'link',
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-cool',
|
||||||
bgColor: 'rgba(0, 150, 136, 0.95)',
|
bgColor: 'rgba(0, 150, 136, 0.95)',
|
||||||
rightText: '看看博主朋友们吧',
|
rightText: '看看博主朋友们吧',
|
||||||
path: '/pages-blog/friend-links/friend-links',
|
path: '/pages-blog/friend-links/friend-links',
|
||||||
@@ -197,7 +204,8 @@ async function handleGetNavList() {
|
|||||||
{
|
{
|
||||||
key: 'disclaimers',
|
key: 'disclaimers',
|
||||||
title: '免责声明',
|
title: '免责声明',
|
||||||
icon: 'map',
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-smirking',
|
||||||
bgColor: 'rgba(121, 85, 72, 0.95)',
|
bgColor: 'rgba(121, 85, 72, 0.95)',
|
||||||
rightText: '博客内容免责声明',
|
rightText: '博客内容免责声明',
|
||||||
path: '/pages-blog/disclaimers/disclaimers',
|
path: '/pages-blog/disclaimers/disclaimers',
|
||||||
@@ -208,7 +216,8 @@ async function handleGetNavList() {
|
|||||||
{
|
{
|
||||||
key: 'contact-blogger',
|
key: 'contact-blogger',
|
||||||
title: '联系博主',
|
title: '联系博主',
|
||||||
icon: 'message',
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-wink',
|
||||||
bgColor: 'rgba(255, 152, 0, 0.95)',
|
bgColor: 'rgba(255, 152, 0, 0.95)',
|
||||||
rightText: '博主常用联系方式',
|
rightText: '博主常用联系方式',
|
||||||
path: '/pages-blog/contact/contact',
|
path: '/pages-blog/contact/contact',
|
||||||
@@ -219,7 +228,8 @@ async function handleGetNavList() {
|
|||||||
{
|
{
|
||||||
key: 'about',
|
key: 'about',
|
||||||
title: '关于项目',
|
title: '关于项目',
|
||||||
icon: 'info',
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-happy-',
|
||||||
bgColor: 'rgba(96, 125, 139, 0.95)',
|
bgColor: 'rgba(96, 125, 139, 0.95)',
|
||||||
rightText: '小莫唐尼开源项目',
|
rightText: '小莫唐尼开源项目',
|
||||||
path: '/pages-blog/about/about',
|
path: '/pages-blog/about/about',
|
||||||
@@ -230,7 +240,8 @@ async function handleGetNavList() {
|
|||||||
{
|
{
|
||||||
key: 'setting',
|
key: 'setting',
|
||||||
title: '偏好设置',
|
title: '偏好设置',
|
||||||
icon: 'settings',
|
iconPrefix: 'uhemoji2-icon',
|
||||||
|
icon: '-tired',
|
||||||
bgColor: 'rgba(121, 134, 203, 0.95)',
|
bgColor: 'rgba(121, 134, 203, 0.95)',
|
||||||
rightText: '首页布局、卡片样式等本地偏好',
|
rightText: '首页布局、卡片样式等本地偏好',
|
||||||
path: '/pages-blog/setting/setting',
|
path: '/pages-blog/setting/setting',
|
||||||
@@ -308,31 +319,27 @@ onPullDownRefresh(() => {
|
|||||||
<!-- 背景遮罩 -->
|
<!-- 背景遮罩 -->
|
||||||
<view class="absolute left-0 top-0 z-0 h-full w-full bg-black/30 backdrop-blur-[2rpx]" />
|
<view class="absolute left-0 top-0 z-0 h-full w-full bg-black/30 backdrop-blur-[2rpx]" />
|
||||||
<view class="relative z-6 h-full flex flex-col items-center justify-center pb-[140rpx] pt-safe">
|
<view class="relative z-6 h-full flex flex-col items-center justify-center pb-[140rpx] pt-safe">
|
||||||
<image
|
<image class="uh-global-card-glass h-20 w-20 rounded-full" :src="bloggerInfo.avatar"
|
||||||
class="uh-global-card-glass h-20 w-20 rounded-full" :src="bloggerInfo.avatar"
|
mode="aspectFill" />
|
||||||
mode="aspectFill"
|
|
||||||
/>
|
|
||||||
<view class="mt-4 text-lg text-white font-bold text-shadow-[0_2rpx_8rpx_rgba(0,0,0,0.4)]">
|
<view class="mt-4 text-lg text-white font-bold text-shadow-[0_2rpx_8rpx_rgba(0,0,0,0.4)]">
|
||||||
{{ bloggerInfo.nickname }}
|
{{ bloggerInfo.nickname }}
|
||||||
</view>
|
</view>
|
||||||
<view
|
<view
|
||||||
class="desc mt-2 px-10 text-center text-[26rpx] text-white/90 leading-relaxed text-shadow-[0_2rpx_8rpx_rgba(0,0,0,0.4)]"
|
class="desc mt-2 px-10 text-center text-[26rpx] text-white/90 leading-relaxed text-shadow-[0_2rpx_8rpx_rgba(0,0,0,0.4)]">
|
||||||
>
|
|
||||||
{{ bloggerInfo.description || '这个博主很懒,竟然没写介绍~' }}
|
{{ bloggerInfo.description || '这个博主很懒,竟然没写介绍~' }}
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<image
|
<image v-if="calcWaveUrl" :src="calcWaveUrl" mode="scaleToFill"
|
||||||
v-if="calcWaveUrl" :src="calcWaveUrl" mode="scaleToFill"
|
class="gif-wave absolute bottom-0 left-0 z-99 h-[100rpx] w-full" style="mix-blend-mode: screen;" />
|
||||||
class="gif-wave absolute bottom-0 left-0 z-99 h-[100rpx] w-full" style="mix-blend-mode: screen;"
|
|
||||||
/>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 站点统计(上浮玻璃卡,与头部衔接) -->
|
<!-- 站点统计(上浮玻璃卡,与头部衔接) -->
|
||||||
<view class="uh-global-card-glass relative z-100 mx-4 flex border rounded-2xl -mt-12">
|
<view class="uh-global-card-glass relative z-100 mx-4 flex border rounded-2xl -mt-12">
|
||||||
<view v-for="item in allStats" :key="item.key" class="flex-1 py-6 text-center">
|
<view v-for="item in allStats" :key="item.key" class="flex-1 py-6 text-center">
|
||||||
<view class="text-lg text-gray-900 font-bold">
|
<wd-count-to
|
||||||
{{ item.value }}
|
:key="`${item.key}-${item.value}`" :start-val="0" :end-val="item.value"
|
||||||
</view>
|
:duration="900" separator="" color="#111827" custom-class="text-lg font-bold"
|
||||||
|
/>
|
||||||
<view class="mt-1 text-xs text-gray-500">
|
<view class="mt-1 text-xs text-gray-500">
|
||||||
{{ item.label }}
|
{{ item.label }}
|
||||||
</view>
|
</view>
|
||||||
@@ -344,18 +351,17 @@ onPullDownRefresh(() => {
|
|||||||
<uh-section-title class="mx-4 mb-3 mt-8">
|
<uh-section-title class="mx-4 mb-3 mt-8">
|
||||||
{{ group.title }}
|
{{ group.title }}
|
||||||
</uh-section-title>
|
</uh-section-title>
|
||||||
<view class="nav-wrap uh-global-card-glass mx-4 overflow-hidden rounded-2xl">
|
<view class="uh-global-card-glass mx-4 overflow-hidden rounded-2xl">
|
||||||
<view
|
<view v-for="(nav, index) in group.items" :key="nav.key"
|
||||||
v-for="(nav, index) in group.items" :key="nav.key"
|
|
||||||
class="nav-item flex items-center justify-between px-4"
|
class="nav-item flex items-center justify-between px-4"
|
||||||
:class="index < group.items.length - 1 ? 'border-b border-b-solid border-black/5' : ''" @click="handleOnNav(nav)"
|
:class="index < group.items.length - 1 ? 'border-b border-b-solid border-black/5' : ''"
|
||||||
>
|
@click="handleOnNav(nav)">
|
||||||
<view class="nav-left flex items-center gap-3 py-3">
|
<view class="nav-left flex items-center gap-3 py-3">
|
||||||
<view
|
<view
|
||||||
class="h-9 w-9 flex items-center justify-center border border-black/5 rounded-xl"
|
class="uh-global-card-glass border uh-shadow-xs h-8 w-8 flex items-center justify-center rounded-xl"
|
||||||
:style="{ backgroundColor: toLightBg(nav.bgColor) }"
|
:style="{ backgroundColor: toLightBg(nav.bgColor) }">
|
||||||
>
|
<wd-icon :class-prefix="nav.iconPrefix" :name="nav.icon" size="36rpx"
|
||||||
<wd-icon :name="nav.icon" size="20px" :color="toSolidColor(nav.bgColor)" />
|
:color="toSolidColor(nav.bgColor)" />
|
||||||
</view>
|
</view>
|
||||||
<text class="nav-title text-sm text-gray-900 font-bold">{{ nav.title }}</text>
|
<text class="nav-title text-sm text-gray-900 font-bold">{{ nav.title }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|||||||
@@ -148,13 +148,11 @@
|
|||||||
onLoad(async () => {
|
onLoad(async () => {
|
||||||
// 检查插件可用性
|
// 检查插件可用性
|
||||||
await checkPluginAvailable()
|
await checkPluginAvailable()
|
||||||
console.log('uniHaloPluginAvailable',uniHaloPluginAvailable.value)
|
|
||||||
if (!uniHaloPluginAvailable.value) {
|
if (!uniHaloPluginAvailable.value) {
|
||||||
uni.stopPullDownRefresh()
|
uni.stopPullDownRefresh()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 开始正常数据请求
|
// 开始正常数据请求
|
||||||
handleGetCategory()
|
handleGetCategory()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// 测试用的 iconfont,可生效
|
// 测试用的 iconfont,可生效
|
||||||
@import './iconfont.css';
|
@import './iconfont.css';
|
||||||
@import './uhemoji-iconfont.css';
|
@import './uhemoji-iconfont.css';
|
||||||
|
@import './uhemoji2-iconfont.css';
|
||||||
|
|
||||||
:root,
|
:root,
|
||||||
page {
|
page {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user