mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-03-01 13:36:55 +08:00
feat(layout): n-layout-sider
& n-layout-footer
& n-layout-header
add inverted
prop.
This commit is contained in:
parent
92e79591ad
commit
c986b375a3
@ -19,6 +19,7 @@
|
||||
- `n-tabs` add `tab-style` prop.
|
||||
- `n-tabs` add `tabs-padding` prop.
|
||||
- `n-tabs` add `default-value` prop.
|
||||
- `n-layout-sider` & `n-layout-footer` & `n-layout-header` add `inverted` prop.
|
||||
|
||||
### Fixes
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
- `n-tabs` 新增 `tab-style` 属性
|
||||
- `n-tabs` 新增 `tabs-padding` 属性
|
||||
- `n-tabs` 新增 `default-value` 属性
|
||||
- `n-layout-sider` & `n-layout-footer` & `n-layout-header` 新增 `inverted` 属性
|
||||
|
||||
### Fixes
|
||||
|
||||
|
@ -166,6 +166,7 @@ const derived: ThemeCommonVars = {
|
||||
bodyColor: base.neutralBody,
|
||||
tagColor: neutral(base.alphaTag),
|
||||
avatarColor: overlay(base.alphaAvatar),
|
||||
invertedColor: base.neutralBase,
|
||||
|
||||
inputColor: overlay(base.alphaInput),
|
||||
codeColor: overlay(base.alphaCode),
|
||||
|
@ -165,6 +165,7 @@ const derived = {
|
||||
bodyColor: base.neutralBody,
|
||||
tagColor: 'rgb(250, 250, 252)',
|
||||
avatarColor: neutral(base.alphaAvatar),
|
||||
invertedColor: 'rgb(0, 20, 40)',
|
||||
|
||||
inputColor: neutral(base.alphaInput),
|
||||
codeColor: 'rgb(244, 244, 248)',
|
||||
|
@ -13,6 +13,7 @@ export const self = (vars: ThemeCommonVars) => {
|
||||
dividerColor,
|
||||
hoverColor,
|
||||
popoverColor,
|
||||
invertedColor,
|
||||
borderRadius,
|
||||
fontSizeSmall,
|
||||
fontSizeMedium,
|
||||
@ -53,7 +54,7 @@ export const self = (vars: ThemeCommonVars) => {
|
||||
optionTextColorHoverInverted: '#FFF',
|
||||
optionTextColorActiveInverted: '#FFF',
|
||||
optionTextColorChildActiveInverted: '#FFF',
|
||||
colorInverted: 'rgb(0, 20, 40)',
|
||||
colorInverted: invertedColor,
|
||||
dividerColorInverted: '#BBB',
|
||||
suffixColorInverted: '#BBB',
|
||||
prefixColorInverted: '#BBB',
|
||||
|
@ -38,6 +38,7 @@ scroll-to
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| bordered | `boolean` | `false` | |
|
||||
| inverted | `boolean` | `false` | Whether to use inverted background. |
|
||||
| position | `'static' \| 'absolute'` | `'static'` | `static` position will make it css position set to `static`. `absolute` position will make it css position set to `absolute` and `left`, `right`, `top` to `0`. `absolute` position is very useful when you want to make content scroll in a fixed container or make the whole page's layout in a fixed position. You may need to change the style of the component to make it display as you expect. |
|
||||
|
||||
### Layout Header Props
|
||||
@ -45,6 +46,7 @@ scroll-to
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| bordered | `boolean` | `false` | |
|
||||
| inverted | `boolean` | `false` | Whether to use inverted background. |
|
||||
| position | `'static' \| 'absolute'` | `'static'` | `static` position will make it css position set to `static`. `absolute` position will make it css position set to `absolute` and `left`, `right`, `bottom` to `0`. `absolute` position is very useful when you want to make content scroll in a fixed container or make the whole page's layout in a fixed position. You may need to change the style of the component to ma ke as you expect. |
|
||||
|
||||
### Layout Sider Props
|
||||
@ -57,6 +59,7 @@ scroll-to
|
||||
| collapsed-width | `number` | `48` | |
|
||||
| content-style | `string \| Object` | `undefined` | Style of scrollable content node. |
|
||||
| default-collapsed | `boolean` | `false` | |
|
||||
| inverted | `boolean` | `false` | Whether to use inverted background. |
|
||||
| native-scrollbar | `boolean` | `true` | Whether to use native scrollbar on itself. If set to `false`, sider will use a naive-ui style scrollbar for content |
|
||||
| position | `'static' \| 'absolute'` | `'static'` | `static` position will make it css position set to `static`. `absolute` position will make it css position set to `absolute` and `left`, `top`, `bottom` to `0`. `absolute` position is very useful when you want to make content scroll in a fixed container or make the whole page's layout in a fixed position. You may need to change the style of the component to make it as you expect. |
|
||||
| show-content | `boolean` | `true` | If set to `false`, sider content will be invisible. |
|
||||
|
@ -18,6 +18,7 @@ absolute
|
||||
scrollbar
|
||||
collapse
|
||||
trigger-button
|
||||
inverted
|
||||
show-sider-content
|
||||
scroll-to
|
||||
```
|
||||
@ -38,6 +39,7 @@ scroll-to
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| bordered | `boolean` | `false` | |
|
||||
| inverted | `boolean` | `false` | 使用反转背景色 |
|
||||
| position | `'static' \| 'absolute'` | `'static'` | `static` 模式将会把 CSS `position` 设为 `static`, `absolute` 模式将会把 CSS `position` 设为 `absolute`,还将 `left`、`right`、`bottom` 设为 `0`。`absolute` 模式在你想将内容在一个固定容器或者将这个页面的布局设为固定位置的时候很有用。你可能需要修改一些 style 来确保它按照你预想的方式展示 |
|
||||
|
||||
### Layout Header Props
|
||||
@ -45,6 +47,7 @@ scroll-to
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| bordered | `boolean` | `false` | |
|
||||
| inverted | `boolean` | `false` | 使用反转背景色 |
|
||||
| position | `'static' \| 'absolute'` | `'static'` | `static` 模式将会把 CSS `position` 设为 `static`, `absolute` 模式将会把 CSS `position` 设为 `absolute`,还将 `left`、`right`、`top` 设为 `0`。`absolute` 模式在你想将内容在一个固定容器或者将这个页面的布局设为固定位置的时候很有用。你可能需要修改一些 style 来确保它按照你预想的方式展示 |
|
||||
|
||||
### Layout Sider Props
|
||||
@ -57,6 +60,7 @@ scroll-to
|
||||
| collapsed-width | `number` | `48` | |
|
||||
| content-style | `string \| Object` | `undefined` | 可滚动内容节点的样式 |
|
||||
| default-collapsed | `boolean` | `false` | |
|
||||
| inverted | `boolean` | `false` | 使用反转背景色 |
|
||||
| native-scrollbar | `boolean` | `true` | 是否在自身使用原生滚动条。如果设定为 `false`, Sider 将会对内容使用 naive-ui 风格的滚动条 |
|
||||
| position | `'static' \| 'absolute'` | `'static'` | `static` 模式将会把 CSS `position` 设为 `static`, `absolute` 模式将会把 CSS `position` 设为 `absolute`,还将 `left`、`top`、`bottom` 设为 `0`。`absolute` 模式在你想将内容在一个固定容器或者将这个页面的布局设为固定位置的时候很有用。你可能需要修改一些 style 来确保它按照你预想的方式展示 |
|
||||
| show-content | `boolean` | `true` | 如果设为 `false`,Sider 的内容将会变透明 |
|
||||
|
138
src/layout/demos/zhCN/inverted.demo.md
Normal file
138
src/layout/demos/zhCN/inverted.demo.md
Normal file
@ -0,0 +1,138 @@
|
||||
# 反转
|
||||
|
||||
使用 `inverted` 增加对比度,可以使用在 header、footer 和 sider 上,可以和 menu 搭配使用。
|
||||
|
||||
```html
|
||||
<n-space vertical>
|
||||
<n-space> <n-switch v-model:value="inverted" /> inverted </n-space>
|
||||
<n-layout>
|
||||
<n-layout-header :inverted="inverted" bordered>
|
||||
Header Header Header
|
||||
<n-menu mode="horizontal" :inverted="inverted" :options="menuOptions" />
|
||||
</n-layout-header>
|
||||
<n-layout has-sider>
|
||||
<n-layout-sider
|
||||
bordered
|
||||
show-trigger
|
||||
collapse-mode="width"
|
||||
:collapsed-width="64"
|
||||
:width="240"
|
||||
:native-scrollbar="false"
|
||||
:inverted="inverted"
|
||||
style="max-height: 320px;"
|
||||
>
|
||||
<n-menu
|
||||
:inverted="inverted"
|
||||
:collapsed-width="64"
|
||||
:collapsed-icon-size="22"
|
||||
:options="menuOptions"
|
||||
/>
|
||||
</n-layout-sider>
|
||||
<n-layout style="max-height: 320px;">
|
||||
<span>内容</span>
|
||||
</n-layout>
|
||||
</n-layout>
|
||||
<n-layout-footer :inverted="inverted" bordered>
|
||||
Footer Footer Footer
|
||||
</n-layout-footer>
|
||||
</n-layout>
|
||||
</n-space>
|
||||
```
|
||||
|
||||
```js
|
||||
import { h, defineComponent, ref } from 'vue'
|
||||
import { NIcon } from 'naive-ui'
|
||||
import {
|
||||
BookOutline as BookIcon,
|
||||
PersonOutline as PersonIcon,
|
||||
WineOutline as WineIcon
|
||||
} from '@vicons/ionicons5'
|
||||
|
||||
function renderIcon (icon) {
|
||||
return () => h(NIcon, null, { default: () => h(icon) })
|
||||
}
|
||||
|
||||
const menuOptions = [
|
||||
{
|
||||
label: '且听风吟',
|
||||
key: 'hear-the-wind-sing',
|
||||
icon: renderIcon(BookIcon)
|
||||
},
|
||||
{
|
||||
label: '1973年的弹珠玩具',
|
||||
key: 'pinball-1973',
|
||||
icon: renderIcon(BookIcon),
|
||||
disabled: true,
|
||||
children: [
|
||||
{
|
||||
label: '鼠',
|
||||
key: 'rat'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '寻羊冒险记',
|
||||
key: 'a-wild-sheep-chase',
|
||||
disabled: true,
|
||||
icon: renderIcon(BookIcon)
|
||||
},
|
||||
{
|
||||
label: '舞,舞,舞',
|
||||
key: 'dance-dance-dance',
|
||||
icon: renderIcon(BookIcon),
|
||||
children: [
|
||||
{
|
||||
type: 'group',
|
||||
label: '人物',
|
||||
key: 'people',
|
||||
children: [
|
||||
{
|
||||
label: '叙事者',
|
||||
key: 'narrator',
|
||||
icon: renderIcon(PersonIcon)
|
||||
},
|
||||
{
|
||||
label: '羊男',
|
||||
key: 'sheep-man',
|
||||
icon: renderIcon(PersonIcon)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '饮品',
|
||||
key: 'beverage',
|
||||
icon: renderIcon(WineIcon),
|
||||
children: [
|
||||
{
|
||||
label: '威士忌',
|
||||
key: 'whisky'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '食物',
|
||||
key: 'food',
|
||||
children: [
|
||||
{
|
||||
label: '三明治',
|
||||
key: 'sandwich'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '过去增多,未来减少',
|
||||
key: 'the-past-increases-the-future-recedes'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
inverted: ref(false),
|
||||
menuOptions
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
@ -9,11 +9,9 @@ import type { ExtractPublicPropTypes } from '../../_utils'
|
||||
|
||||
const layoutFooterProps = {
|
||||
...(useTheme.props as ThemeProps<LayoutTheme>),
|
||||
inverted: Boolean,
|
||||
position: positionProp,
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
bordered: Boolean
|
||||
}
|
||||
|
||||
export type LayoutFooterProps = ExtractPublicPropTypes<typeof layoutFooterProps>
|
||||
@ -36,13 +34,21 @@ export default defineComponent({
|
||||
cssVars: computed(() => {
|
||||
const {
|
||||
common: { cubicBezierEaseInOut },
|
||||
self: { footerBorderColor, footerColor }
|
||||
self
|
||||
} = themeRef.value
|
||||
return {
|
||||
'--bezier': cubicBezierEaseInOut,
|
||||
'--color': footerColor,
|
||||
'--border-color': footerBorderColor
|
||||
const vars: any = {
|
||||
'--bezier': cubicBezierEaseInOut
|
||||
}
|
||||
if (props.inverted) {
|
||||
vars['--color'] = self.footerColorInverted
|
||||
vars['--text-color'] = self.textColorInverted
|
||||
vars['--border-color'] = self.footerBorderColorInverted
|
||||
} else {
|
||||
vars['--color'] = self.footerColor
|
||||
vars['--text-color'] = self.textColor
|
||||
vars['--border-color'] = self.footerBorderColor
|
||||
}
|
||||
return vars
|
||||
})
|
||||
}
|
||||
},
|
||||
@ -52,11 +58,9 @@ export default defineComponent({
|
||||
<div
|
||||
class={[
|
||||
`${mergedClsPrefix}-layout-footer`,
|
||||
{
|
||||
[`${mergedClsPrefix}-layout-footer--${this.position}-positioned`]: this
|
||||
.position,
|
||||
[`${mergedClsPrefix}-layout-footer--bordered`]: this.bordered
|
||||
}
|
||||
this.position &&
|
||||
`${mergedClsPrefix}-layout-footer--${this.position}-positioned`,
|
||||
this.bordered && `${mergedClsPrefix}-layout-footer--bordered`
|
||||
]}
|
||||
style={this.cssVars as CSSProperties}
|
||||
>
|
||||
|
@ -9,6 +9,7 @@ import { ExtractPublicPropTypes } from '../../_utils'
|
||||
|
||||
const headerProps = {
|
||||
position: positionProp,
|
||||
inverted: Boolean,
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
@ -38,13 +39,21 @@ export default defineComponent({
|
||||
cssVars: computed(() => {
|
||||
const {
|
||||
common: { cubicBezierEaseInOut },
|
||||
self: { headerColor, headerBorderColor }
|
||||
self
|
||||
} = themeRef.value
|
||||
return {
|
||||
'--bezier': cubicBezierEaseInOut,
|
||||
'--header-color': headerColor,
|
||||
'--header-border-color': headerBorderColor
|
||||
const vars: any = {
|
||||
'--bezier': cubicBezierEaseInOut
|
||||
}
|
||||
if (props.inverted) {
|
||||
vars['--color'] = self.headerColorInverted
|
||||
vars['--text-color'] = self.textColorInverted
|
||||
vars['--border-color'] = self.headerBorderColorInverted
|
||||
} else {
|
||||
vars['--color'] = self.headerColor
|
||||
vars['--text-color'] = self.textColor
|
||||
vars['--border-color'] = self.headerBorderColor
|
||||
}
|
||||
return vars
|
||||
})
|
||||
}
|
||||
},
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
ref,
|
||||
CSSProperties,
|
||||
toRef,
|
||||
inject
|
||||
inject,
|
||||
provide
|
||||
} from 'vue'
|
||||
import { useConfig, useTheme } from '../../_mixins'
|
||||
import type { ThemeProps } from '../../_mixins'
|
||||
@ -19,16 +20,13 @@ import type { LayoutTheme } from '../styles'
|
||||
import style from './styles/layout-sider.cssr'
|
||||
import ToggleButton from './ToggleButton'
|
||||
import ToggleBar from './ToggleBar'
|
||||
import { positionProp } from './interface'
|
||||
import { layoutSiderInjectionKey, positionProp } from './interface'
|
||||
import { useMergedState } from 'vooks'
|
||||
import { layoutInjectionKey } from './Layout'
|
||||
|
||||
const layoutSiderProps = {
|
||||
position: positionProp,
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
bordered: Boolean,
|
||||
collapsedWidth: {
|
||||
type: Number,
|
||||
default: 48
|
||||
@ -49,10 +47,7 @@ const layoutSiderProps = {
|
||||
type: Boolean as PropType<boolean | undefined>,
|
||||
default: undefined
|
||||
},
|
||||
defaultCollapsed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
defaultCollapsed: Boolean,
|
||||
showContent: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
@ -69,6 +64,7 @@ const layoutSiderProps = {
|
||||
type: Number,
|
||||
default: 300
|
||||
},
|
||||
inverted: Boolean,
|
||||
scrollbarProps: Object as PropType<
|
||||
Partial<ScrollbarProps> & { style: CSSProperties }
|
||||
>,
|
||||
@ -174,6 +170,9 @@ export default defineComponent({
|
||||
if (onCollapse) call(onCollapse)
|
||||
}
|
||||
}
|
||||
provide(layoutSiderInjectionKey, {
|
||||
collapsedRef: mergedCollapsedRef
|
||||
})
|
||||
const { mergedClsPrefixRef } = useConfig(props)
|
||||
const themeRef = useTheme(
|
||||
'Layout',
|
||||
@ -197,22 +196,30 @@ export default defineComponent({
|
||||
cssVars: computed(() => {
|
||||
const {
|
||||
common: { cubicBezierEaseInOut },
|
||||
self: {
|
||||
siderColor,
|
||||
siderToggleButtonColor,
|
||||
siderBorderColor,
|
||||
siderToggleBarColor,
|
||||
siderToggleBarColorHover
|
||||
}
|
||||
self
|
||||
} = themeRef.value
|
||||
return {
|
||||
const {
|
||||
siderToggleButtonColor,
|
||||
siderToggleBarColor,
|
||||
siderToggleBarColorHover
|
||||
} = self
|
||||
const vars: any = {
|
||||
'--bezier': cubicBezierEaseInOut,
|
||||
'--sider-color': siderColor,
|
||||
'--sider-border-color': siderBorderColor,
|
||||
'--sider-toggle-button-color': siderToggleButtonColor,
|
||||
'--sider-toggle-bar-color': siderToggleBarColor,
|
||||
'--sider-toggle-bar-color-hover': siderToggleBarColorHover
|
||||
'--toggle-button-color': siderToggleButtonColor,
|
||||
'--toggle-bar-color': siderToggleBarColor,
|
||||
'--toggle-bar-color-hover': siderToggleBarColorHover
|
||||
}
|
||||
if (props.inverted) {
|
||||
vars['--color'] = self.siderColorInverted
|
||||
vars['--text-color'] = self.textColorInverted
|
||||
vars['--border-color'] = self.siderBorderColorInverted
|
||||
vars.__invertScrollbar = self.__invertScrollbar
|
||||
} else {
|
||||
vars['--color'] = self.siderColor
|
||||
vars['--text-color'] = self.textColor
|
||||
vars['--border-color'] = self.siderBorderColor
|
||||
}
|
||||
return vars
|
||||
})
|
||||
}
|
||||
},
|
||||
@ -224,15 +231,12 @@ export default defineComponent({
|
||||
class={[
|
||||
`${mergedClsPrefix}-layout-sider`,
|
||||
`${mergedClsPrefix}-layout-sider--${this.position}-positioned`,
|
||||
{
|
||||
[`${mergedClsPrefix}-layout-sider--bordered`]: this.bordered,
|
||||
[`${mergedClsPrefix}-layout-sider--collapsed`]: this
|
||||
.mergedCollapsed,
|
||||
[`${mergedClsPrefix}-layout-sider--show-content`]: this.showContent
|
||||
}
|
||||
this.bordered && `${mergedClsPrefix}-layout-sider--bordered`,
|
||||
this.mergedCollapsed && `${mergedClsPrefix}-layout-sider--collapsed`,
|
||||
this.showContent && `${mergedClsPrefix}-layout-sider--show-content`
|
||||
]}
|
||||
style={[
|
||||
this.cssVars as any,
|
||||
this.cssVars,
|
||||
{
|
||||
maxWidth: this.styleMaxWidth,
|
||||
width: formatLength(this.width)
|
||||
@ -248,6 +252,16 @@ export default defineComponent({
|
||||
contentStyle={this.contentStyle}
|
||||
theme={this.mergedTheme.peers.Scrollbar}
|
||||
themeOverrides={this.mergedTheme.peerOverrides.Scrollbar}
|
||||
// here is a hack, since in light theme the scrollbar color is dark,
|
||||
// we need to invert it in light color...
|
||||
builtinThemeOverrides={
|
||||
this.inverted && this.cssVars.__invertScrollbar === 'true'
|
||||
? {
|
||||
colorHover: 'rgba(255, 255, 255, .4)',
|
||||
color: 'rgba(255, 255, 255, .3)'
|
||||
}
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{this.$slots}
|
||||
</NScrollbar>
|
||||
@ -259,9 +273,6 @@ export default defineComponent({
|
||||
{this.$slots}
|
||||
</div>
|
||||
)}
|
||||
{this.bordered ? (
|
||||
<div class={`${mergedClsPrefix}-layout-sider__border`} />
|
||||
) : null}
|
||||
{this.showTrigger ? (
|
||||
this.showTrigger === 'arrow-circle' ? (
|
||||
<ToggleButton
|
||||
|
@ -1,4 +1,8 @@
|
||||
import { PropType } from 'vue'
|
||||
import { InjectionKey, PropType, Ref } from 'vue'
|
||||
|
||||
export const layoutSiderInjectionKey: InjectionKey<{
|
||||
collapsedRef: Ref<boolean>
|
||||
}> = Symbol('layoutSiderInjection')
|
||||
|
||||
export const positionProp = {
|
||||
type: String as PropType<'static' | 'absolute'>,
|
||||
|
@ -4,10 +4,13 @@ import { cB, cM } from '../../../_utils/cssr'
|
||||
// --bezier
|
||||
// --color
|
||||
// --border-color
|
||||
// --text-color
|
||||
export default cB('layout-footer', `
|
||||
transition:
|
||||
color .3s var(--bezier),
|
||||
background-color .3s var(--bezier),
|
||||
border-color .3s var(--bezier);
|
||||
color: var(--text-color);
|
||||
background-color: var(--color);
|
||||
box-sizing: border-box;
|
||||
`, [
|
||||
|
@ -2,16 +2,19 @@ import { cB, cM } from '../../../_utils/cssr'
|
||||
|
||||
// vars:
|
||||
// --bezier
|
||||
// --header-color
|
||||
// --header-border-color
|
||||
// --text-color
|
||||
// --color
|
||||
// --border-color
|
||||
export default cB('layout-header', `
|
||||
transition:
|
||||
color .3s var(--bezier),
|
||||
background-color .3s var(--bezier),
|
||||
box-shadow .3s var(--bezier),
|
||||
border-color .3s var(--bezier);
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
background-color: var(--header-color);
|
||||
background-color: var(--color);
|
||||
color: var(--text-color);
|
||||
`, [
|
||||
cM('absolute-positioned', `
|
||||
position: absolute;
|
||||
@ -20,6 +23,6 @@ export default cB('layout-header', `
|
||||
top: 0;
|
||||
`),
|
||||
cM('bordered', `
|
||||
border-bottom: solid 1px var(--header-border-color);
|
||||
border-bottom: solid 1px var(--border-color);
|
||||
`)
|
||||
])
|
||||
|
@ -2,22 +2,26 @@ import { c, cB, cE, cM } from '../../../_utils/cssr'
|
||||
|
||||
// vars:
|
||||
// --bezier
|
||||
// --sider-color
|
||||
// --sider-border-color
|
||||
// --sider-toggle-button-color
|
||||
// --sider-toggle-bar-color
|
||||
// --sider-toggle-bar-color-hover
|
||||
// --color
|
||||
// --text-color
|
||||
// --border-color
|
||||
// --toggle-button-color
|
||||
// --toggle-bar-color
|
||||
// --toggle-bar-color-hover
|
||||
export default cB('layout-sider', `
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
color: var(--text-color);
|
||||
transition:
|
||||
color .3s var(--bezier),
|
||||
border-color .3s var(--bezier),
|
||||
min-width .3s var(--bezier),
|
||||
max-width .3s var(--bezier),
|
||||
transform .3s var(--bezier),
|
||||
background-color .3s var(--bezier);
|
||||
background-color: var(--sider-color);
|
||||
background-color: var(--color);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
`, [
|
||||
@ -32,7 +36,7 @@ export default cB('layout-sider', `
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translateX(50%) translateY(-50%);
|
||||
fill: var(--sider-toggle-button-color);
|
||||
fill: var(--toggle-button-color);
|
||||
`),
|
||||
cB('layout-toggle-bar', `
|
||||
cursor: pointer;
|
||||
@ -75,11 +79,11 @@ export default cB('layout-sider', `
|
||||
])
|
||||
]),
|
||||
cE('top, bottom', {
|
||||
backgroundColor: 'var(--sider-toggle-bar-color)'
|
||||
backgroundColor: 'var(--toggle-bar-color)'
|
||||
}),
|
||||
c('&:hover', [
|
||||
cE('top, bottom', {
|
||||
backgroundColor: 'var(--sider-toggle-bar-color-hover)'
|
||||
backgroundColor: 'var(--toggle-bar-color-hover)'
|
||||
})
|
||||
])
|
||||
]),
|
||||
@ -92,6 +96,7 @@ export default cB('layout-sider', `
|
||||
transition: background-color .3s var(--bezier);
|
||||
`),
|
||||
cE('content', `
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
@ -115,9 +120,7 @@ export default cB('layout-sider', `
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
`),
|
||||
cM('bordered', [
|
||||
cE('border', {
|
||||
backgroundColor: 'var(--sider-border-color)'
|
||||
})
|
||||
])
|
||||
cM('bordered', `
|
||||
border-right: 1px solid var(--border-color);
|
||||
`)
|
||||
])
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { commonDark } from '../../_styles/common'
|
||||
import { scrollbarDark } from '../../scrollbar/styles'
|
||||
import type { LayoutTheme } from './light'
|
||||
import { self } from './light'
|
||||
import { composite } from 'seemly'
|
||||
|
||||
const layoutDark: LayoutTheme = {
|
||||
name: 'Layout',
|
||||
@ -10,11 +10,35 @@ const layoutDark: LayoutTheme = {
|
||||
Scrollbar: scrollbarDark
|
||||
},
|
||||
self (vars) {
|
||||
const commonSelf = self(vars)
|
||||
const { cardColor } = vars
|
||||
commonSelf.siderToggleButtonColor = 'rgba(255, 255, 255, .3)'
|
||||
commonSelf.footerColor = cardColor
|
||||
return commonSelf
|
||||
const {
|
||||
textColor2,
|
||||
bodyColor,
|
||||
cardColor,
|
||||
dividerColor,
|
||||
scrollbarColor,
|
||||
scrollbarColorHover
|
||||
} = vars
|
||||
return {
|
||||
textColor: textColor2,
|
||||
textColorInverted: textColor2,
|
||||
color: bodyColor,
|
||||
headerColor: cardColor,
|
||||
headerColorInverted: cardColor,
|
||||
footerColor: cardColor,
|
||||
footerColorInverted: cardColor,
|
||||
headerBorderColor: dividerColor,
|
||||
headerBorderColorInverted: dividerColor,
|
||||
footerBorderColor: dividerColor,
|
||||
footerBorderColorInverted: dividerColor,
|
||||
siderBorderColor: dividerColor,
|
||||
siderBorderColorInverted: dividerColor,
|
||||
siderColor: cardColor,
|
||||
siderColorInverted: cardColor,
|
||||
siderToggleButtonColor: 'rgba(255, 255, 255, .3)',
|
||||
siderToggleBarColor: composite(bodyColor, scrollbarColor),
|
||||
siderToggleBarColorHover: composite(bodyColor, scrollbarColorHover),
|
||||
__invertScrollbar: 'false'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,20 +12,29 @@ export const self = (vars: ThemeCommonVars) => {
|
||||
dividerColor,
|
||||
actionColor,
|
||||
scrollbarColor,
|
||||
scrollbarColorHover
|
||||
scrollbarColorHover,
|
||||
invertedColor
|
||||
} = vars
|
||||
return {
|
||||
textColor: textColor2,
|
||||
textColorInverted: '#FFF',
|
||||
color: bodyColor,
|
||||
headerColor: cardColor,
|
||||
headerColorInverted: invertedColor,
|
||||
footerColor: actionColor,
|
||||
footerColorInverted: invertedColor,
|
||||
headerBorderColor: dividerColor,
|
||||
headerBorderColorInverted: invertedColor,
|
||||
footerBorderColor: dividerColor,
|
||||
footerBorderColorInverted: invertedColor,
|
||||
siderBorderColor: dividerColor,
|
||||
siderBorderColorInverted: invertedColor,
|
||||
siderColor: cardColor,
|
||||
siderColorInverted: invertedColor,
|
||||
siderToggleButtonColor: 'rgba(0, 0, 0, .15)',
|
||||
siderToggleBarColor: composite(bodyColor, scrollbarColor),
|
||||
siderToggleBarColorHover: composite(bodyColor, scrollbarColorHover)
|
||||
siderToggleBarColorHover: composite(bodyColor, scrollbarColorHover),
|
||||
__invertScrollbar: 'true'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,24 +4,18 @@ Set `inverted` to add contrast.
|
||||
|
||||
```html
|
||||
<n-space vertical>
|
||||
<n-space>
|
||||
<n-switch v-model:value="collapsed" /> collapsed
|
||||
<n-switch v-model:value="inverted" /> inverted
|
||||
</n-space>
|
||||
<n-space> <n-switch v-model:value="inverted" /> inverted </n-space>
|
||||
<n-layout has-sider>
|
||||
<n-layout-sider
|
||||
bordered
|
||||
collapse-mode="width"
|
||||
:collapsed-width="64"
|
||||
:width="240"
|
||||
:collapsed="collapsed"
|
||||
show-trigger
|
||||
@collapse="collapsed = true"
|
||||
@expand="collapsed = false"
|
||||
:inverted="inverted"
|
||||
>
|
||||
<n-menu
|
||||
:inverted="inverted"
|
||||
:collapsed="collapsed"
|
||||
:collapsed-width="64"
|
||||
:collapsed-icon-size="22"
|
||||
:options="menuOptions"
|
||||
@ -126,8 +120,6 @@ const menuOptions = [
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
activeKey: ref(null),
|
||||
collapsed: ref(false),
|
||||
inverted: ref(false),
|
||||
menuOptions
|
||||
}
|
||||
|
@ -4,28 +4,21 @@
|
||||
|
||||
```html
|
||||
<n-space vertical>
|
||||
<n-space>
|
||||
<n-switch v-model:value="collapsed" /> collapsed
|
||||
<n-switch v-model:value="inverted" /> inverted
|
||||
</n-space>
|
||||
<n-space> <n-switch v-model:value="inverted" /> inverted </n-space>
|
||||
<n-layout has-sider>
|
||||
<n-layout-sider
|
||||
bordered
|
||||
collapse-mode="width"
|
||||
:collapsed-width="64"
|
||||
:width="240"
|
||||
:collapsed="collapsed"
|
||||
show-trigger
|
||||
@collapse="collapsed = true"
|
||||
@expand="collapsed = false"
|
||||
:inverted="inverted"
|
||||
>
|
||||
<n-menu
|
||||
:inverted="inverted"
|
||||
:collapsed="collapsed"
|
||||
:collapsed-width="64"
|
||||
:collapsed-icon-size="22"
|
||||
:options="menuOptions"
|
||||
v-model:value="activeKey"
|
||||
/>
|
||||
</n-layout-sider>
|
||||
<n-layout>
|
||||
@ -126,8 +119,6 @@ const menuOptions = [
|
||||
export default defineComponent({
|
||||
setup () {
|
||||
return {
|
||||
activeKey: ref(null),
|
||||
collapsed: ref(false),
|
||||
inverted: ref(false),
|
||||
menuOptions
|
||||
}
|
||||
|
@ -8,7 +8,8 @@ import {
|
||||
PropType,
|
||||
ExtractPropTypes,
|
||||
InjectionKey,
|
||||
CSSProperties
|
||||
CSSProperties,
|
||||
inject
|
||||
} from 'vue'
|
||||
import { createTreeMate, Key } from 'treemate'
|
||||
import { useCompitable, useMergedState } from 'vooks'
|
||||
@ -28,6 +29,7 @@ import {
|
||||
OnUpdateValueImpl,
|
||||
OnUpdateKeysImpl
|
||||
} from './interface'
|
||||
import { layoutSiderInjectionKey } from '../../layout/src/interface'
|
||||
|
||||
const menuProps = {
|
||||
...(useTheme.props as ThemeProps<MenuTheme>),
|
||||
@ -46,8 +48,8 @@ const menuProps = {
|
||||
default: undefined
|
||||
},
|
||||
collapsed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
type: Boolean as PropType<boolean | undefined>,
|
||||
default: undefined
|
||||
},
|
||||
collapsedWidth: {
|
||||
type: Number,
|
||||
@ -170,6 +172,12 @@ export default defineComponent({
|
||||
mergedClsPrefixRef
|
||||
)
|
||||
|
||||
const layoutSider = inject(layoutSiderInjectionKey, null)
|
||||
|
||||
const mergedCollapsedRef = computed(() => {
|
||||
return props.collapsed ?? layoutSider?.collapsedRef.value ?? false
|
||||
})
|
||||
|
||||
const treeMateRef = computed(() =>
|
||||
createTreeMate<MenuOption, MenuGroupOption>(
|
||||
props.items || props.options,
|
||||
@ -205,6 +213,7 @@ export default defineComponent({
|
||||
})
|
||||
provide(menuInjectionKey, {
|
||||
props,
|
||||
mergedCollapsedRef,
|
||||
mergedThemeRef: themeRef,
|
||||
mergedValueRef,
|
||||
mergedExpandedKeysRef,
|
||||
@ -265,6 +274,7 @@ export default defineComponent({
|
||||
activePath: activePathRef,
|
||||
tmNodes: tmNodesRef,
|
||||
mergedTheme: themeRef,
|
||||
mergedCollapsed: mergedCollapsedRef,
|
||||
cssVars: computed(() => {
|
||||
const { inverted } = props
|
||||
const {
|
||||
@ -331,7 +341,7 @@ export default defineComponent({
|
||||
class={[
|
||||
`${mergedClsPrefix}-menu`,
|
||||
`${mergedClsPrefix}-menu--${this.mode}`,
|
||||
this.collapsed && `${mergedClsPrefix}-menu--collapsed`
|
||||
this.mergedCollapsed && `${mergedClsPrefix}-menu--collapsed`
|
||||
]}
|
||||
style={this.cssVars as CSSProperties}
|
||||
>
|
||||
|
@ -48,7 +48,7 @@ export default defineComponent({
|
||||
setup (props) {
|
||||
const MenuChild = useMenuChild(props)
|
||||
const { NMenu, NSubmenu } = MenuChild
|
||||
const { props: menuProps } = NMenu
|
||||
const { props: menuProps, mergedCollapsedRef } = NMenu
|
||||
const mergedDisabledRef = computed(() => {
|
||||
const { disabled } = props
|
||||
if (NSubmenu?.mergedDisabledRef.value) return true
|
||||
@ -67,7 +67,7 @@ export default defineComponent({
|
||||
}
|
||||
function handleClick (): void {
|
||||
if (!mergedDisabledRef.value) {
|
||||
if (!menuProps.collapsed) {
|
||||
if (!mergedCollapsedRef.value) {
|
||||
NMenu.toggleExpand(props.internalKey)
|
||||
}
|
||||
doClick()
|
||||
@ -94,7 +94,7 @@ export default defineComponent({
|
||||
}),
|
||||
collapsed: computed(() => {
|
||||
if (menuProps.mode === 'horizontal') return false
|
||||
if (menuProps.collapsed) {
|
||||
if (mergedCollapsedRef.value) {
|
||||
return true
|
||||
}
|
||||
return !NMenu.mergedExpandedKeysRef.value.includes(props.internalKey)
|
||||
@ -102,7 +102,7 @@ export default defineComponent({
|
||||
dropdownEnabled: computed(() => {
|
||||
return (
|
||||
!mergedDisabledRef.value &&
|
||||
(menuProps.mode === 'horizontal' || menuProps.collapsed)
|
||||
(menuProps.mode === 'horizontal' || mergedCollapsedRef.value)
|
||||
)
|
||||
}),
|
||||
handlePopoverShowChange,
|
||||
|
@ -29,13 +29,12 @@ export default cB('menu', `
|
||||
color: var(--item-text-color);
|
||||
overflow: hidden;
|
||||
transition: background-color .3s var(--bezier);
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
font-size: var(--font-size);
|
||||
padding-bottom: 6px;
|
||||
`, [
|
||||
cM('horizontal', {
|
||||
display: 'flex',
|
||||
display: 'inline-flex',
|
||||
paddingBottom: 0
|
||||
}, [
|
||||
cB('submenu', {
|
||||
|
@ -13,7 +13,6 @@ const ICON_MARGIN_RIGHT = 8
|
||||
export interface MenuInjection {
|
||||
props: {
|
||||
mode: 'vertical' | 'horizontal'
|
||||
collapsed: boolean
|
||||
iconSize: number
|
||||
collapsedIconSize: number | undefined
|
||||
indent: number
|
||||
@ -21,6 +20,7 @@ export interface MenuInjection {
|
||||
collapsedWidth: number
|
||||
disabled: boolean
|
||||
}
|
||||
mergedCollapsedRef: Ref<boolean>
|
||||
invertedRef: Ref<boolean>
|
||||
isHorizontalRef: Ref<boolean>
|
||||
mergedClsPrefixRef: Ref<string>
|
||||
@ -56,7 +56,7 @@ export interface UseMenuChild {
|
||||
export function useMenuChild (props: UseMenuChildProps): UseMenuChild {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const NMenu = inject(menuInjectionKey)!
|
||||
const { props: menuProps } = NMenu
|
||||
const { props: menuProps, mergedCollapsedRef } = NMenu
|
||||
const NSubmenu = inject(submenuInjectionKey, null)
|
||||
const NMenuOptionGroup = inject<MenuOptionGroupInjection | null>(
|
||||
menuItemGroupInjectionKey,
|
||||
@ -79,7 +79,7 @@ export function useMenuChild (props: UseMenuChildProps): UseMenuChild {
|
||||
)
|
||||
})
|
||||
const activeIconSizeRef = computed(() => {
|
||||
if (!horizontalRef.value && props.root && menuProps.collapsed) {
|
||||
if (!horizontalRef.value && props.root && mergedCollapsedRef.value) {
|
||||
return menuProps.collapsedIconSize ?? menuProps.iconSize
|
||||
} else {
|
||||
return menuProps.iconSize
|
||||
@ -91,7 +91,7 @@ export function useMenuChild (props: UseMenuChildProps): UseMenuChild {
|
||||
const { root, isGroup } = props
|
||||
const mergedRootIndent = rootIndent === undefined ? indent : rootIndent
|
||||
if (root) {
|
||||
if (menuProps.collapsed) {
|
||||
if (mergedCollapsedRef.value) {
|
||||
return collapsedWidth / 2 - maxIconSizeRef.value / 2
|
||||
}
|
||||
return mergedRootIndent
|
||||
@ -113,7 +113,7 @@ export function useMenuChild (props: UseMenuChildProps): UseMenuChild {
|
||||
const { root } = props
|
||||
if (horizontalRef.value) return ICON_MARGIN_RIGHT
|
||||
if (!root) return ICON_MARGIN_RIGHT
|
||||
if (!menuProps.collapsed) return ICON_MARGIN_RIGHT
|
||||
if (!mergedCollapsedRef.value) return ICON_MARGIN_RIGHT
|
||||
const mergedRootIndent = rootIndent === undefined ? indent : rootIndent
|
||||
return (
|
||||
mergedRootIndent +
|
||||
|
@ -56,7 +56,7 @@ export const self = (vars: ThemeCommonVars) => {
|
||||
arrowColorHover: primaryColorHover,
|
||||
arrowColorChildActive: primaryColor,
|
||||
arrowColorActive: primaryColor,
|
||||
colorInverted: 'rgb(0, 20, 40)',
|
||||
colorInverted: '#0000',
|
||||
itemColorActiveInverted: primaryColor,
|
||||
itemColorActiveCollapsedInverted: primaryColor,
|
||||
borderColorHorizontal: '#0000',
|
||||
|
@ -19,7 +19,7 @@ display-directive
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| addable | `boolean \| { disabled?: boolean }` | `false` | Whether to show add button. Only works when type is `'card'`. |
|
||||
| default-value | `string \| number` | `name` of the first tab | |
|
||||
| default-value | `string \| number` | name prop of the first tab | |
|
||||
| closable | `boolean` | `false` | Whether to allow tab to close, Only works when type is `'card'`. |
|
||||
| justify-content | `'space-between' \| 'space-around' \| 'space-evenly'` | `undefined` | |
|
||||
| label-size | `'small' \| 'medium' \| 'large' \| 'huge'` | `'medium'` | Size of tabs. Only works when type is `'line'`. |
|
||||
|
@ -21,7 +21,7 @@ line-debug
|
||||
| --- | --- | --- | --- |
|
||||
| addable | `boolean \| { disabled?: boolean }` | `false` | 是否展示增加按钮,只在 type 为 `'card'` 时生效 |
|
||||
| closable | `boolean` | `false` | 是否允许 tab 关闭,只在 type 为 `'card'` 时生效 |
|
||||
| default-value | `string \| number` | 第一个标签页的 `name` | |
|
||||
| default-value | `string \| number` | 第一个标签页的 name 属性 | |
|
||||
| justify-content | `'space-between' \| 'space-around' \| 'space-evenly'` | `undefined` | |
|
||||
| label-size | `'small' \| 'medium' \| 'large' \| 'huge'` | `'medium'` | 标签的尺寸,只对线型的 Tabs 生效 |
|
||||
| show-divider | `boolean` | `false` | 是否展示分割线,只在 type 为 `'line'` 时生效 |
|
||||
|
Loading…
Reference in New Issue
Block a user