Skip to content

Commit

Permalink
feat: improve page component (#5013)
Browse files Browse the repository at this point in the history
* feat: `page` component support fixed header

* docs: `page`  component documentation

* docs: Improve `props` types of `page`

* docs: improve `fixedHeader` description of `page`

* fix: `page` header border color with fixedHeader

* feat: add `headerClass` for `Page`
  • Loading branch information
mynetfan authored Dec 4, 2024
1 parent 24b9aa4 commit 17c7ce8
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 7 deletions.
10 changes: 10 additions & 0 deletions docs/.vitepress/config/zh.mts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,16 @@ function sidebarComponents(): DefaultTheme.SidebarItem[] {
},
],
},
{
collapsed: false,
text: '布局组件',
items: [
{
link: 'layout-ui/page',
text: 'Page 页面',
},
],
},
{
collapsed: false,
text: '通用组件',
Expand Down
4 changes: 4 additions & 0 deletions docs/src/components/introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

:::

## 布局组件

布局组件一般在页面内容区域用作顶层容器组件,提供一些统一的布局样式和基本功能。

## 通用组件

通用组件是一些常用的组件,比如弹窗、抽屉、表单等。大部分基于 `Tailwind CSS` 实现,可适用于不同 UI 组件库的应用。
45 changes: 45 additions & 0 deletions docs/src/components/layout-ui/page.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
outline: deep
---

# Page 常规页面组件

提供一个常规页面布局的组件,包括头部、内容区域、底部三个部分。

::: info 写在前面

本组件是一个基本布局组件。如果有更多的通用页面布局需求(比如双列布局等),可以根据实际需求自行封装。

:::

## 基础用法

`Page`作为你的业务页面的根组件即可。

### Props

| 属性名 | 描述 | 类型 | 默认值 |
| --- | --- | --- | --- |
| title | 页面标题 | `string\|slot` | - |
| description | 页面描述(标题下的内容) | `string\|slot` | - |
| contentClass | 内容区域的class | `string` | - |
| headerClass | 头部区域的class | `string` | - |
| footerClass | 底部区域的class | `string` | - |
| autoContentHeight | 自动调整内容区域的高度 | `boolean` | `false` |
| fixedHeader | 固定头部在页面内容区域顶部,在滚动时保持可见 | `boolean` | `false` |

::: tip 注意

如果`title``description``extra`三者均未提供有效内容(通过`props`或者`slots`均可),则页面头部区域不会渲染。

:::

### Slots

| 插槽名称 | 描述 |
| ----------- | ------------ |
| default | 页面内容 |
| title | 页面标题 |
| description | 页面描述 |
| extra | 页面头部右侧 |
| footer | 页面底部 |
2 changes: 1 addition & 1 deletion packages/@core/ui-kit/layout-ui/src/vben-layout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,7 @@ function handleHeaderToggle() {

<div
ref="contentRef"
class="flex flex-1 flex-col overflow-hidden transition-all duration-300 ease-in"
class="flex flex-1 flex-col transition-all duration-300 ease-in"
>
<div
:class="[
Expand Down
1 change: 1 addition & 0 deletions packages/effects/common-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"dependencies": {
"@vben-core/form-ui": "workspace:*",
"@vben-core/popup-ui": "workspace:*",
"@vben-core/preferences": "workspace:*",
"@vben-core/shadcn-ui": "workspace:*",
"@vben-core/shared": "workspace:*",
"@vben/constants": "workspace:*",
Expand Down
44 changes: 41 additions & 3 deletions packages/effects/common-ui/src/components/page/page.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
<script setup lang="ts">
import { computed, nextTick, onMounted, ref, useTemplateRef } from 'vue';
import {
computed,
nextTick,
onMounted,
ref,
type StyleValue,
useTemplateRef,
} from 'vue';
import { preferences } from '@vben-core/preferences';
import { cn } from '@vben-core/shared/utils';
interface Props {
title?: string;
Expand All @@ -9,6 +19,10 @@ interface Props {
* 根据content可见高度自适应
*/
autoContentHeight?: boolean;
/** 头部固定 */
fixedHeader?: boolean;
headerClass?: string;
footerClass?: string;
}
defineOptions({
Expand All @@ -20,6 +34,7 @@ const {
description = '',
autoContentHeight = false,
title = '',
fixedHeader = false,
} = defineProps<Props>();
const headerHeight = ref(0);
Expand All @@ -29,6 +44,17 @@ const shouldAutoHeight = ref(false);
const headerRef = useTemplateRef<HTMLDivElement>('headerRef');
const footerRef = useTemplateRef<HTMLDivElement>('footerRef');
const headerStyle = computed<StyleValue>(() => {
return fixedHeader
? {
position: 'sticky',
zIndex: 200,
top:
preferences.header.mode === 'fixed' ? 'var(--vben-header-height)' : 0,
}
: undefined;
});
const contentStyle = computed(() => {
if (autoContentHeight) {
return {
Expand Down Expand Up @@ -69,7 +95,14 @@ onMounted(() => {
$slots.extra
"
ref="headerRef"
class="bg-card relative px-6 py-4"
:class="
cn(
'bg-card relative px-6 py-4',
headerClass,
fixedHeader ? 'border-border border-b' : '',
)
"
:style="headerStyle"
>
<slot name="title">
<div v-if="title" class="mb-2 flex text-lg font-semibold">
Expand All @@ -95,7 +128,12 @@ onMounted(() => {
<div
v-if="$slots.footer"
ref="footerRef"
class="bg-card align-center absolute bottom-0 left-0 right-0 flex px-6 py-4"
:class="
cn(
footerClass,
'bg-card align-center absolute bottom-0 left-0 right-0 flex px-6 py-4',
)
"
>
<slot name="footer"></slot>
</div>
Expand Down
23 changes: 20 additions & 3 deletions playground/src/views/examples/form/basic.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
<script lang="ts" setup>
import { ref } from 'vue';
import { Page } from '@vben/common-ui';
import { Button, Card, message } from 'ant-design-vue';
import { Button, Card, message, TabPane, Tabs } from 'ant-design-vue';
import dayjs from 'dayjs';
import { useVbenForm } from '#/adapter/form';
import DocButton from '../doc-button.vue';
const activeTab = ref('basic');
const [BaseForm, baseFormApi] = useVbenForm({
// 所有表单项共用,可单独在表单内覆盖
commonConfig: {
Expand Down Expand Up @@ -331,18 +335,31 @@ function handleSetFormValue() {
<Page
content-class="flex flex-col gap-4"
description="表单组件基础示例,请注意,该页面用到的参数代码会添加一些简单注释,方便理解,请仔细查看。"
fixed-header
header-class="pb-0"
title="表单组件"
>
<template #description>
<div class="text-muted-foreground">
<p>
表单组件基础示例,请注意,该页面用到的参数代码会添加一些简单注释,方便理解,请仔细查看。
</p>
</div>
<Tabs v-model:active-key="activeTab" :tab-bar-style="{ marginBottom: 0 }">
<TabPane key="basic" tab="基础示例" />
<TabPane key="layout" tab="自定义布局" />
</Tabs>
</template>
<template #extra>
<DocButton path="/components/common-ui/vben-form" />
</template>
<Card title="基础示例">
<Card v-show="activeTab === 'basic'" title="基础示例">
<template #extra>
<Button type="primary" @click="handleSetFormValue">设置表单值</Button>
</template>
<BaseForm />
</Card>
<Card title="使用tailwind自定义布局">
<Card v-show="activeTab === 'layout'" title="使用tailwind自定义布局">
<CustomLayoutForm />
</Card>
</Page>
Expand Down
1 change: 1 addition & 0 deletions playground/src/views/examples/modal/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ function openFormModal() {
<template>
<Page
description="弹窗组件常用于在不离开当前页面的情况下,显示额外的信息、表单或操作提示,更多api请查看组件文档。"
fixed-header
title="弹窗组件示例"
>
<template #extra>
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 17c7ce8

Please sign in to comment.