feat(page-header)

This commit is contained in:
07akioni 2021-04-03 11:29:37 +08:00
parent e423b2e737
commit 6e1cca769d
20 changed files with 544 additions and 7 deletions

View File

@ -2,6 +2,15 @@
## Pending
### Feats
- Add `n-page-header` component.
- `n-statistic` add label slot.
### Refactors
- Refactor `n-statistic`'s style
### Fixes
- Fix `n-collapse` content is truncated by `overflow: hidden`.

View File

@ -2,6 +2,15 @@
## Pending
### Feats
- 添加 `n-page-header` 组件
- `n-statistic` 增加 label slot
### Refactors
- 重构 `n-statistic` 样式
### Fixes
- 修正 `n-collapse` 内容被 `overflow: hidden` 截断

View File

@ -371,6 +371,11 @@ export const enComponentRoutes = [
path: 'n-mention',
component: () => import('../../src/mention/demos/enUS/index.demo-entry.md')
},
{
path: 'n-page-header',
component: () =>
import('../../src/page-header/demos/enUS/index.demo-entry.md')
},
// deprecated
{
path: 'n-nimbus-service-layout',
@ -682,6 +687,11 @@ export const zhComponentRoutes = [
path: 'n-mention',
component: () => import('../../src/mention/demos/zhCN/index.demo-entry.md')
},
{
path: 'n-page-header',
component: () =>
import('../../src/page-header/demos/zhCN/index.demo-entry.md')
},
// deprecated
{
path: 'n-nimbus-service-layout',

View File

@ -175,6 +175,12 @@ export function createComponentMenuOptions ({ lang, theme, mode }) {
enSuffix: true,
path: '/n-icon'
},
{
en: 'PageHeader',
zh: '页头',
enSuffix: true,
path: '/n-page-header'
},
{
en: 'Tag',
zh: '标签',

View File

@ -0,0 +1,13 @@
import { h, defineComponent } from 'vue'
export default defineComponent({
name: 'ArrowBack',
render () {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M0 0h24v24H0V0z" fill="none"></path>
<path d="M19 11H7.83l4.88-4.88c.39-.39.39-1.03 0-1.42-.39-.39-1.02-.39-1.41 0l-6.59 6.59c-.39.39-.39 1.02 0 1.41l6.59 6.59c.39.39 1.02.39 1.41 0 .39-.39.39-1.02 0-1.41L7.83 13H19c.55 0 1-.45 1-1s-.45-1-1-1z"></path>
</svg>
)
}
})

View File

@ -4,13 +4,7 @@ export default defineComponent({
name: 'ArrowDown',
render () {
return (
<svg
width="28px"
height="28px"
viewBox="0 0 28 28"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
>
<svg viewBox="0 0 28 28" version="1.1" xmlns="http://www.w3.org/2000/svg">
<g stroke="none" stroke-width="1" fill-rule="evenodd">
<g fill-rule="nonzero">
<path d="M23.7916,15.2664 C24.0788,14.9679 24.0696,14.4931 23.7711,14.206 C23.4726,13.9188 22.9978,13.928 22.7106,14.2265 L14.7511,22.5007 L14.7511,3.74792 C14.7511,3.33371 14.4153,2.99792 14.0011,2.99792 C13.5869,2.99792 13.2511,3.33371 13.2511,3.74793 L13.2511,22.4998 L5.29259,14.2265 C5.00543,13.928 4.53064,13.9188 4.23213,14.206 C3.93361,14.4931 3.9244,14.9679 4.21157,15.2664 L13.2809,24.6944 C13.6743,25.1034 14.3289,25.1034 14.7223,24.6944 L23.7916,15.2664 Z" />

View File

@ -29,3 +29,4 @@ export { default as ClearIcon } from './Clear'
export { default as ChevronDownFilledIcon } from './ChevronDownFilled'
export { default as ToIcon } from './To'
export { default as RetryIcon } from './Retry'
export { default as ArrowBackIcon } from './ArrowBack'

View File

@ -41,6 +41,7 @@ export * from './mention'
export * from './message'
export * from './modal'
export * from './notification'
export * from './page-header'
export * from './pagination'
export * from './popconfirm'
export * from './popover'

View File

@ -38,6 +38,7 @@ import type { MentionTheme } from '../../mention/styles'
import type { MessageTheme } from '../../message/styles'
import type { ModalTheme } from '../../modal/styles'
import type { NotificationTheme } from '../../notification/styles'
import type { PageHeaderTheme } from '../../page-header/styles'
import type { PaginationTheme } from '../../pagination/styles'
import type { PopconfirmTheme } from '../../popconfirm/styles'
import type { PopoverTheme } from '../../popover/styles'
@ -117,6 +118,7 @@ export interface GlobalThemeWithoutCommon {
Message?: MessageTheme
Modal?: ModalTheme
Notification?: NotificationTheme
PageHeader?: PageHeaderTheme
Pagination?: PaginationTheme
Popconfirm?: PopconfirmTheme
Popover?: PopoverTheme

View File

@ -0,0 +1,87 @@
# Basic
```html
<n-page-header
subtitle="Make your hearing sense better understand vision."
@back="handleBack"
>
<n-grid :cols="5">
<n-gi>
<n-statistic label="Episode" value="125" />
</n-gi>
<n-gi>
<n-statistic label="Guests" value="22" />
</n-gi>
<n-gi>
<n-statistic label="Applogies" value="36" />
</n-gi>
<n-gi>
<n-statistic label="Topics" value="83" />
</n-gi>
<n-gi>
<n-statistic label="Reference Links" value="2,346" />
</n-gi>
</n-grid>
<template #title>
<a href="https://anyway.fm/" style="text-decoration: none; color: inherit;"
>Anyway.FM</a
>
</template>
<template #header>
<n-breadcrumb>
<n-breadcrumb-item>Podcast</n-breadcrumb-item>
<n-breadcrumb-item>Best Collection</n-breadcrumb-item>
<n-breadcrumb-item>Ultimate Best Collection</n-breadcrumb-item>
<n-breadcrumb-item>Anyway.FM</n-breadcrumb-item>
</n-breadcrumb>
</template>
<template #avatar>
<n-avatar
src="https://cdnimg103.lizhi.fm/user/2017/02/04/2583325032200238082_160x160.jpg"
/>
</template>
<template #extra>
<n-space>
<n-button>Urge Update</n-button>
<n-dropdown :options="options" placement="bottom-start">
<n-button :bordered="false" style="padding: 0 4px">···</n-button>
</n-dropdown>
</n-space>
</template>
<template #footer>As of April 3, 2021</template>
</n-page-header>
```
```js
import { defineComponent } from 'vue'
import { useMessage } from 'naive-ui'
import { EllipsisHorizontal } from '@vicons/ionicons5'
export default defineComponent({
components: {
EllipsisHorizontal
},
setup () {
const message = useMessage()
return {
handleBack () {
message.info('[onBack]')
},
options: [
{
label: 'Urge Update',
key: '1'
},
{
label: 'Urge Update',
key: '2'
},
{
label: 'Urge Update',
key: '3'
}
]
}
}
})
```

View File

@ -0,0 +1,30 @@
<!--single-column-->
# PageHeader
## Demos
```demo
basic
```
## Props
| Name | Type | Default | Description |
| -------- | ------------ | ----------- | ----------- |
| extra | `string` | `undefined` | |
| subtitle | `string` | `undefined` | |
| title | `string` | `undefined` | |
| on-back | `() => void` | `undefined` | |
## Slots
| Name | Parameters | Description |
| -------- | ---------- | ----------- |
| avatar | `()` | |
| header | `()` | |
| default | `()` | |
| extra | `()` | |
| footer | `()` | |
| subtitle | `()` | |
| title | `()` | |

View File

@ -0,0 +1,84 @@
# 基础用法
```html
<n-page-header subtitle="让你的听觉更懂视觉" @back="handleBack">
<n-grid :cols="5">
<n-gi>
<n-statistic label="正片" value="125 集" />
</n-gi>
<n-gi>
<n-statistic label="嘉宾" value="22 位" />
</n-gi>
<n-gi>
<n-statistic label="道歉" value="36 次" />
</n-gi>
<n-gi>
<n-statistic label="话题" value="83 个" />
</n-gi>
<n-gi>
<n-statistic label="参考链接" value="2,346 个" />
</n-gi>
</n-grid>
<template #title>
<a href="https://anyway.fm/" style="text-decoration: none; color: inherit;"
>Anyway.FM</a
>
</template>
<template #header>
<n-breadcrumb>
<n-breadcrumb-item>播客</n-breadcrumb-item>
<n-breadcrumb-item>精选</n-breadcrumb-item>
<n-breadcrumb-item>超级精选</n-breadcrumb-item>
<n-breadcrumb-item>Anyway.FM</n-breadcrumb-item>
</n-breadcrumb>
</template>
<template #avatar>
<n-avatar
src="https://cdnimg103.lizhi.fm/user/2017/02/04/2583325032200238082_160x160.jpg"
/>
</template>
<template #extra>
<n-space>
<n-button>催更</n-button>
<n-dropdown :options="options" placement="bottom-start">
<n-button :bordered="false" style="padding: 0 4px">···</n-button>
</n-dropdown>
</n-space>
</template>
<template #footer>截止到 2021 年 4 月 3 日</template>
</n-page-header>
```
```js
import { defineComponent } from 'vue'
import { useMessage } from 'naive-ui'
import { EllipsisHorizontal } from '@vicons/ionicons5'
export default defineComponent({
components: {
EllipsisHorizontal
},
setup () {
const message = useMessage()
return {
handleBack () {
message.info('[onBack]')
},
options: [
{
label: '催更',
key: '1'
},
{
label: '催更',
key: '2'
},
{
label: '催更',
key: '3'
}
]
}
}
})
```

View File

@ -0,0 +1,30 @@
<!--single-column-->
# 页头 PageHeader
## 演示
```demo
basic
```
## Props
| 名称 | 类型 | 默认值 | 说明 |
| -------- | ------------ | ----------- | ---- |
| extra | `string` | `undefined` | |
| subtitle | `string` | `undefined` | |
| title | `string` | `undefined` | |
| on-back | `() => void` | `undefined` | |
## Slots
| 名称 | 参数 | 说明 |
| -------- | ---- | ---- |
| avatar | `()` | |
| header | `()` | |
| default | `()` | |
| extra | `()` | |
| footer | `()` | |
| subtitle | `()` | |
| title | `()` | |

1
src/page-header/index.ts Normal file
View File

@ -0,0 +1 @@
export { default as NPageHeader } from './src/PageHeader'

View File

@ -0,0 +1,123 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { h, defineComponent, computed, CSSProperties, PropType } from 'vue'
import { useTheme } from '../../_mixins'
import type { ThemeProps } from '../../_mixins'
import { pageHeaderLight } from '../styles/light'
import type { PageHeaderTheme } from '../styles/light'
import style from './styles/index.cssr'
import { ArrowBackIcon } from '../../_internal/icons'
import { NBaseIcon } from '../../_internal'
export default defineComponent({
name: 'PageHeader',
props: {
...(useTheme.props as ThemeProps<PageHeaderTheme>),
title: String,
subtitle: String,
extra: String,
onBack: Function as PropType<() => void>
},
setup (props) {
const themeRef = useTheme(
'PageHeader',
'PageHeader',
style,
pageHeaderLight,
props
)
return {
cssVars: computed(() => {
const {
self: {
titleTextColor,
subtitleTextColor,
backColor,
fontSize,
titleFontSize,
backSize,
titleFontWeight,
backColorHover,
backColorPressed
},
common: { cubicBezierEaseInOut }
} = themeRef.value
return {
'--title-text-color': titleTextColor,
'--title-font-size': titleFontSize,
'--title-font-weight': titleFontWeight,
'--font-size': fontSize,
'--back-size': backSize,
'--subtitle-text-color': subtitleTextColor,
'--back-color': backColor,
'--back-color-hover': backColorHover,
'--back-color-pressed': backColorPressed,
'--bezier': cubicBezierEaseInOut
}
})
}
},
render () {
const { onBack, title, subtitle, extra, $slots } = this
const {
title: titleSlot,
subtitle: subtitleSlot,
extra: extraSlot,
default: defaultSlot,
header: headerSlot,
avatar: avatarSlot,
footer: footerSlot
} = $slots
const showBack = onBack
const showTitle = title || titleSlot
const showSubtitle = subtitle || subtitleSlot
const showExtra = extra || extraSlot
return (
<div style={this.cssVars as CSSProperties}>
{headerSlot ? (
<div class="n-page-header-header" key="breadcrumn">
{headerSlot()}
</div>
) : null}
<div class="n-page-header" key="header">
<div class="n-page-header__main" key="back">
{showBack ? (
<div class="n-page-header__back" onClick={onBack}>
<NBaseIcon>
{{
default: () => <ArrowBackIcon />
}}
</NBaseIcon>
</div>
) : null}
{avatarSlot ? (
<div class="n-page-header__avatar">{avatarSlot()}</div>
) : null}
{showTitle ? (
<div class="n-page-header__title" key="title">
{title || titleSlot!()}
</div>
) : null}
{showSubtitle ? (
<div class="n-page-header__subtitle" key="subtitle">
{subtitle || subtitleSlot!()}
</div>
) : null}
</div>
{showExtra ? (
<div class="n-page-header__extra">{extra || extraSlot!()}</div>
) : null}
</div>
{defaultSlot ? (
<div class="n-page-header-content" key="content">
{defaultSlot()}
</div>
) : null}
{footerSlot ? (
<div class="n-page-header-footer" key="footer">
{footerSlot()}
</div>
) : null}
</div>
)
}
})

View File

@ -0,0 +1,66 @@
import { c, cB, cE } from '../../../_utils/cssr'
// vars:
// --title-font-size
// --title-text-color
// --font-size
// --subtitle-text-color
// --back-color
// --back-color-hover
// --back-color-pressed
// --back-size
// --title-font-weight
// --bezier
export default c([
cB('page-header-header', `
margin-bottom: 20px;
`),
cB('page-header', `
display: flex;
align-items: center;
justify-content: space-between;
line-height: 1.5;
font-size: var(--font-size);
`, [
cE('main', `
display: flex;
flex-wrap: nowrap;
align-items: center;
`),
cE('back', `
display: flex;
margin-right: 16px;
font-size: var(--back-size);
cursor: pointer;
color: var(--back-color);
transition: color .3s var(--bezier);
`, [
c('&:hover', 'color: var(--back-color-hover);'),
c('&:active', 'color: var(--back-color-pressed);')
]),
cE('avatar', `
display: flex;
margin-right: 12px
`),
cE('title', `
margin-right: 16px;
transition: color .3s var(--bezier);
font-size: var(--title-font-size);
font-weight: var(--title-font-weight);
color: var(--title-text-color);
`),
cE('subtitle', `
font-size: 14px;
transition: color .3s var(--bezier);
color: var(--subtitle-text-color);
`)
]),
cB('page-header-content', `
margin-top: 20px;
font-size: var(--font-size);
`),
cB('page-header-footer', `
margin-top: 20px;
font-size: var(--font-size);
`)
])

View File

@ -0,0 +1,4 @@
export default {
titleFontSize: '18px',
backSize: '22px'
}

View File

@ -0,0 +1,29 @@
import type { PageHeaderTheme } from './light'
import { commonDark } from '../../_styles/common'
import common from './_common'
export const pageHeaderDark: PageHeaderTheme = {
name: 'PageHeader',
common: commonDark,
self (vars) {
const {
textColor1,
textColor2,
textColor3,
fontSize,
fontWeightStrong,
primaryColorHover,
primaryColorPressed
} = vars
return {
...common,
titleFontWeight: fontWeightStrong,
fontSize,
titleTextColor: textColor1,
backColor: textColor2,
backColorHover: primaryColorHover,
backColorPressed: primaryColorPressed,
subtitleTextColor: textColor3
}
}
}

View File

@ -0,0 +1,3 @@
export { pageHeaderLight } from './light'
export type { PageHeaderTheme, PageHeaderThemeVars } from './light'
export { pageHeaderDark } from './dark'

View File

@ -0,0 +1,35 @@
import { createTheme } from '../../_mixins'
import { commonLight } from '../../_styles/common'
import type { ThemeCommonVars } from '../../_styles/common'
import common from './_common'
function self (vars: ThemeCommonVars) {
const {
textColor1,
textColor2,
textColor3,
fontSize,
fontWeightStrong,
primaryColorHover,
primaryColorPressed
} = vars
return {
...common,
titleFontWeight: fontWeightStrong,
fontSize,
titleTextColor: textColor1,
backColor: textColor2,
backColorHover: primaryColorHover,
backColorPressed: primaryColorPressed,
subtitleTextColor: textColor3
}
}
export const pageHeaderLight = createTheme({
name: 'PageHeader',
common: commonLight,
self
})
export type PageHeaderThemeVars = ReturnType<typeof self>
export type PageHeaderTheme = typeof pageHeaderLight