mirror of
https://github.com/tusen-ai/naive-ui.git
synced 2025-02-11 13:10:26 +08:00
feat(float-button): new component (#5627)
* feat: create template * feat: add demo * feat: change to css * feat: add style * feat: add demo * feat: add demo * feat: add group * feat: add docs * feat: add log * fix: style error * feat: add docs
This commit is contained in:
parent
2bf5229543
commit
da39759039
@ -22,6 +22,7 @@
|
||||
- `n-split` adds `size` prop and `on-update:size` prop.
|
||||
- `n-split` adds `watch-props` prop, closes [#5526](https://github.com/tusen-ai/naive-ui/issues/5526).
|
||||
- `n-drawer` adds `borderRadius` theme variable.
|
||||
- adds `n-float-button` component.
|
||||
|
||||
### i18n
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
- `n-split` 新增 `size` 和 `on-update:size` 属性
|
||||
- `n-split` 新增 `watch-props` 属性,关闭 [#5526](https://github.com/tusen-ai/naive-ui/issues/5526)
|
||||
- `n-drawer` 新增 `borderRadius` 主题变量
|
||||
- 新增 `n-float-button` 组件
|
||||
|
||||
### i18n
|
||||
|
||||
|
@ -551,6 +551,11 @@ export const enComponentRoutes = [
|
||||
{
|
||||
path: 'split',
|
||||
component: () => import('../../src/split/demos/enUS/index.demo-entry.md')
|
||||
},
|
||||
{
|
||||
path: 'float-button',
|
||||
component: () =>
|
||||
import('../../src/float-button/demos/enUS/index.demo-entry.md')
|
||||
}
|
||||
]
|
||||
|
||||
@ -945,6 +950,11 @@ export const zhComponentRoutes = [
|
||||
{
|
||||
path: 'split',
|
||||
component: () => import('../../src/split/demos/zhCN/index.demo-entry.md')
|
||||
},
|
||||
{
|
||||
path: 'float-button',
|
||||
component: () =>
|
||||
import('../../src/float-button/demos/zhCN/index.demo-entry.md')
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -289,6 +289,13 @@ export function createComponentMenuOptions ({ lang, theme, mode }) {
|
||||
zh: '水印',
|
||||
enSuffix: true,
|
||||
path: '/watermark'
|
||||
},
|
||||
{
|
||||
en: 'Float Button',
|
||||
zh: '浮动按钮',
|
||||
enSuffix: true,
|
||||
path: '/float-button',
|
||||
isNew: true
|
||||
}
|
||||
]
|
||||
}),
|
||||
|
@ -35,6 +35,8 @@ export * from './ellipsis'
|
||||
export * from './empty'
|
||||
export * from './flex'
|
||||
export * from './form'
|
||||
export * from './float-button'
|
||||
export * from './float-button-group'
|
||||
export * from './global-style'
|
||||
export * from './gradient-text'
|
||||
export * from './grid'
|
||||
|
@ -31,6 +31,7 @@ import type { EllipsisTheme } from '../../ellipsis/styles'
|
||||
import type { EmptyTheme } from '../../empty/styles'
|
||||
import type { EquationTheme } from '../../equation/styles'
|
||||
import type { FormTheme } from '../../form/styles'
|
||||
import type { FloatButtonTheme } from '../../float-button/styles'
|
||||
import type { GradientTextTheme } from '../../gradient-text/styles'
|
||||
import type { IconTheme } from '../../icon/styles'
|
||||
import type { IconWrapperTheme } from '../../icon-wrapper/styles'
|
||||
@ -100,6 +101,7 @@ import type { RowTheme } from '../../legacy-grid/styles'
|
||||
import type { Katex } from './katex'
|
||||
import type { SplitTheme } from '../../split/styles'
|
||||
import type { FlexTheme } from '../../flex/styles'
|
||||
import type { FloatButtonGroupTheme } from '../../float-button-group/styles'
|
||||
|
||||
export interface GlobalThemeWithoutCommon {
|
||||
Alert?: AlertTheme
|
||||
@ -136,6 +138,8 @@ export interface GlobalThemeWithoutCommon {
|
||||
Equation?: EquationTheme
|
||||
Flex?: FlexTheme
|
||||
Form?: FormTheme
|
||||
FloatButton?: FloatButtonTheme
|
||||
FloatButtonGroup?: FloatButtonGroupTheme
|
||||
GradientText?: GradientTextTheme
|
||||
Icon?: IconTheme
|
||||
IconWrapper?: IconWrapperTheme
|
||||
|
5
src/float-button-group/index.ts
Normal file
5
src/float-button-group/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export {
|
||||
default as NFloatButtonGroup,
|
||||
floatButtonGroupProps
|
||||
} from './src/FloatButtonGroup'
|
||||
export type { FloatButtonGroupProps } from './src/FloatButtonGroup'
|
124
src/float-button-group/src/FloatButtonGroup.tsx
Normal file
124
src/float-button-group/src/FloatButtonGroup.tsx
Normal file
@ -0,0 +1,124 @@
|
||||
import {
|
||||
h,
|
||||
type PropType,
|
||||
defineComponent,
|
||||
computed,
|
||||
type CSSProperties
|
||||
} from 'vue'
|
||||
import type { Size } from '../../button/src/interface'
|
||||
import { type ThemeProps, useConfig, useTheme } from '../../_mixins'
|
||||
import type { ExtractPublicPropTypes } from '../../_utils'
|
||||
import style from './styles/index.cssr'
|
||||
import floatButtonGroupLight, {
|
||||
type FloatButtonGroupTheme
|
||||
} from '../styles/light'
|
||||
|
||||
export interface ButtonGroupInjection {
|
||||
size?: Size | undefined
|
||||
}
|
||||
|
||||
export const floatButtonGroupProps = {
|
||||
...(useTheme.props as ThemeProps<FloatButtonGroupTheme>),
|
||||
width: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: 'auto'
|
||||
},
|
||||
height: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: 'auto'
|
||||
},
|
||||
left: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: undefined
|
||||
},
|
||||
right: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: 40
|
||||
},
|
||||
top: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: undefined
|
||||
},
|
||||
bottom: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: 40
|
||||
},
|
||||
radius: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: 22
|
||||
},
|
||||
backgroundColor: String,
|
||||
vertical: Boolean
|
||||
} as const
|
||||
|
||||
export type FloatButtonGroupProps = ExtractPublicPropTypes<
|
||||
typeof floatButtonGroupProps
|
||||
>
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FloatButtonGroup',
|
||||
props: floatButtonGroupProps,
|
||||
setup (props) {
|
||||
const { mergedClsPrefixRef, inlineThemeDisabled } = useConfig(props)
|
||||
|
||||
const themeRef = useTheme(
|
||||
'FloatButtonGroup',
|
||||
'-float-button-group',
|
||||
style,
|
||||
floatButtonGroupLight,
|
||||
props,
|
||||
mergedClsPrefixRef
|
||||
)
|
||||
|
||||
const cssVarsRef = computed(() => {
|
||||
const {
|
||||
self: { color, textColor, boxShadow, boxShadowHover, boxShadowPressed },
|
||||
common: { cubicBezierEaseInOut }
|
||||
} = themeRef.value
|
||||
return {
|
||||
'--n-bezier': cubicBezierEaseInOut,
|
||||
'--n-box-shadow': boxShadow,
|
||||
'--n-box-shadow-hover': boxShadowHover,
|
||||
'--n-box-shadow-pressed': boxShadowPressed,
|
||||
'--n-color': color,
|
||||
'--n-text-color': textColor,
|
||||
left: formatNumber(props.left),
|
||||
right: formatNumber(props.right),
|
||||
top: formatNumber(props.top),
|
||||
bottom: formatNumber(props.bottom),
|
||||
width: formatNumber(props.width),
|
||||
height: formatNumber(props.height),
|
||||
borderRadius: formatNumber(props.radius),
|
||||
backgroundColor: props.backgroundColor
|
||||
}
|
||||
})
|
||||
|
||||
const formatNumber = (
|
||||
value: number | string | undefined
|
||||
): string | undefined => {
|
||||
if (typeof value === 'number') return `${value}px`
|
||||
return value
|
||||
}
|
||||
|
||||
return {
|
||||
cssVars: inlineThemeDisabled ? undefined : cssVarsRef,
|
||||
mergedClsPrefix: mergedClsPrefixRef,
|
||||
formatNumber
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const { mergedClsPrefix, cssVars } = this
|
||||
return (
|
||||
<div
|
||||
class={[
|
||||
`${mergedClsPrefix}-float-button-group`,
|
||||
this.vertical && `${mergedClsPrefix}-float-button-group--vertical`
|
||||
]}
|
||||
style={cssVars as CSSProperties}
|
||||
role="group"
|
||||
>
|
||||
{this.$slots}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
24
src/float-button-group/src/styles/index.cssr.ts
Normal file
24
src/float-button-group/src/styles/index.cssr.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { cB, cM, cNotM } from '../../../_utils/cssr/index'
|
||||
|
||||
export default cB('float-button-group', `
|
||||
position: fixed;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--n-text-color);
|
||||
transition:
|
||||
color .3s var(--n-bezier),
|
||||
box-shadow .3s var(--n-bezier),
|
||||
background-color .3s var(--n-bezier);
|
||||
`, [
|
||||
cNotM('vertical', {
|
||||
flexDirection: 'row'
|
||||
}, [
|
||||
|
||||
]),
|
||||
cM('vertical', {
|
||||
flexDirection: 'column'
|
||||
}, [
|
||||
])
|
||||
])
|
19
src/float-button-group/styles/dark.ts
Normal file
19
src/float-button-group/styles/dark.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { commonDark } from '../../_styles/common'
|
||||
import type { FloatButtonGroupTheme } from './light'
|
||||
|
||||
const floatButtonGroupDark: FloatButtonGroupTheme = {
|
||||
name: 'FloatButtonGroup',
|
||||
common: commonDark,
|
||||
self (vars) {
|
||||
const { popoverColor, textColor2 } = vars
|
||||
return {
|
||||
color: popoverColor,
|
||||
textColor: textColor2,
|
||||
boxShadow: '0 2px 8px 0px rgba(0, 0, 0, .12)',
|
||||
boxShadowHover: '0 2px 12px 0px rgba(0, 0, 0, .18)',
|
||||
boxShadowPressed: '0 2px 12px 0px rgba(0, 0, 0, .18)'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default floatButtonGroupDark
|
3
src/float-button-group/styles/index.ts
Normal file
3
src/float-button-group/styles/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export { default as floatButtonGroupDark } from './dark'
|
||||
export { default as floatButtonGroupLight } from './light'
|
||||
export type { FloatButtonGroupTheme } from './light'
|
25
src/float-button-group/styles/light.ts
Normal file
25
src/float-button-group/styles/light.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { type Theme } from '../../_mixins'
|
||||
import { type ThemeCommonVars } from '../../config-provider'
|
||||
import { commonLight } from '../../styles'
|
||||
|
||||
const self = (vars: ThemeCommonVars) => {
|
||||
const { popoverColor, textColor2 } = vars
|
||||
return {
|
||||
color: popoverColor,
|
||||
textColor: textColor2,
|
||||
boxShadow: '0 2px 8px 0px rgba(0, 0, 0, .12)',
|
||||
boxShadowHover: '0 2px 12px 0px rgba(0, 0, 0, .18)',
|
||||
boxShadowPressed: '0 2px 12px 0px rgba(0, 0, 0, .18)'
|
||||
}
|
||||
}
|
||||
|
||||
export type FloatButtonGroupThemeVars = ReturnType<typeof self>
|
||||
|
||||
const themeLight: Theme<'FloatButtonGroup', FloatButtonGroupThemeVars> = {
|
||||
name: 'FloatButtonGroup',
|
||||
common: commonLight,
|
||||
self
|
||||
}
|
||||
|
||||
export default themeLight
|
||||
export type FloatButtonGroupTheme = typeof themeLight
|
64
src/float-button/demos/enUS/badge.demo.vue
Normal file
64
src/float-button/demos/enUS/badge.demo.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<markdown>
|
||||
# Badge
|
||||
|
||||
You can put a hover button with the number of badges on any element.
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<div style="height: 200px; transform: translate(0)">
|
||||
<n-float-button :right="0" :bottom="0">
|
||||
<n-badge :value="9" :offset="[6, -8]">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
<n-float-button :right="70" :bottom="0">
|
||||
<n-badge :value="100" :max="99" :offset="[6, -8]">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
<n-float-button :right="142" :bottom="0">
|
||||
<n-badge dot :offset="[4, -4]">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
<n-float-button :right="142" :bottom="0">
|
||||
<n-badge dot :offset="[4, -4]">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
<n-float-button :right="0" :bottom="60">
|
||||
<n-badge value="New" :offset="[10, -10]">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
<n-float-button :right="70" :bottom="60">
|
||||
<n-badge :value="9" :offset="[6, -8]" color="grey">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { AlarmOutline as AlarmOutlineIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
AlarmOutlineIcon
|
||||
}
|
||||
})
|
||||
</script>
|
39
src/float-button/demos/enUS/basic.demo.vue
Normal file
39
src/float-button/demos/enUS/basic.demo.vue
Normal file
@ -0,0 +1,39 @@
|
||||
<markdown>
|
||||
# Basic
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<div style="height: 200px; transform: translate(0)">
|
||||
<n-float-button :right="0" :bottom="0">
|
||||
<n-icon :size="24">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-float-button>
|
||||
<n-float-button :left="0" :bottom="0">
|
||||
<n-icon :size="24">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-float-button>
|
||||
<n-float-button :right="0" :top="0">
|
||||
<n-icon :size="24">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-float-button>
|
||||
<n-float-button :left="0" :top="0">
|
||||
<n-icon :size="24">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-float-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
CashIcon
|
||||
}
|
||||
})
|
||||
</script>
|
49
src/float-button/demos/enUS/custom.demo.vue
Normal file
49
src/float-button/demos/enUS/custom.demo.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<markdown>
|
||||
# Custom Dom
|
||||
|
||||
You can put any element you want.
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<div style="height: 200px; transform: translate(0)">
|
||||
<n-float-button
|
||||
:right="0"
|
||||
:bottom="60"
|
||||
height="auto"
|
||||
width="auto"
|
||||
:radius="10"
|
||||
>
|
||||
<n-flex
|
||||
vertical
|
||||
:style="{ padding: '4px', textAlign: 'center' }"
|
||||
align="center"
|
||||
>
|
||||
<n-icon :size="24">
|
||||
<document-icon />
|
||||
</n-icon>
|
||||
<span> Document </span>
|
||||
</n-flex>
|
||||
</n-float-button>
|
||||
|
||||
<n-float-button :right="0" :left="0" :bottom="0" width="100%" :radius="10">
|
||||
<n-flex align="center">
|
||||
<n-icon :size="24">
|
||||
<document-icon />
|
||||
</n-icon>
|
||||
<span> Document </span>
|
||||
</n-flex>
|
||||
</n-float-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Document as DocumentIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
DocumentIcon
|
||||
}
|
||||
})
|
||||
</script>
|
81
src/float-button/demos/enUS/group.demo.vue
Normal file
81
src/float-button/demos/enUS/group.demo.vue
Normal file
@ -0,0 +1,81 @@
|
||||
<markdown>
|
||||
# Float Button Group
|
||||
|
||||
Elements can be arbitrarily combined to achieve more functionality.
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<div style="height: 200px; transform: translate(0)">
|
||||
<n-float-button-group
|
||||
:left="0"
|
||||
right="auto"
|
||||
:bottom="0"
|
||||
vertical
|
||||
background-color="lightgrey"
|
||||
>
|
||||
<n-button
|
||||
tertiary
|
||||
circle
|
||||
type="primary"
|
||||
:style="{ marginBottom: '20px' }"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button tertiary circle type="info" :style="{ marginBottom: '20px' }">
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button
|
||||
tertiary
|
||||
circle
|
||||
type="success"
|
||||
:style="{ marginBottom: '20px' }"
|
||||
>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</n-button>
|
||||
<n-button tertiary circle type="warning">
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
</n-float-button-group>
|
||||
|
||||
<n-float-button-group :right="0" :bottom="0">
|
||||
<n-flex vertical>
|
||||
<n-button tertiary circle type="primary">
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button tertiary circle type="info">
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button tertiary circle type="success">
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</n-button>
|
||||
<n-button tertiary circle type="warning">
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</n-float-button-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
CashIcon
|
||||
}
|
||||
})
|
||||
</script>
|
44
src/float-button/demos/enUS/index.demo-entry.md
Normal file
44
src/float-button/demos/enUS/index.demo-entry.md
Normal file
@ -0,0 +1,44 @@
|
||||
# Float Button
|
||||
|
||||
Like `Back Top`, more appearance level, more interaction.
|
||||
|
||||
Available since `NEXT_VERSION`.
|
||||
|
||||
## Demos
|
||||
|
||||
```demo
|
||||
basic.vue
|
||||
badge.vue
|
||||
tooltip.vue
|
||||
custom.vue
|
||||
group.vue
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Float Button Props
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| width | `number \| string` | `40` | The width. |
|
||||
| height | `number \| string` | `40` | The height. |
|
||||
| left | `number \| string` | `40` | The width from the left side of the page. |
|
||||
| right | `number \| string` | `40` | The width from the right side of the page. |
|
||||
| top | `number \| string` | `40` | The height from the top of the page. |
|
||||
| bottom | `number \| string` | `40` | The height from the bottom of the page. |
|
||||
| background-color | `string` | `#ffffff` | Background color. |
|
||||
| radius | `number \| string` | `22` | The radius. |
|
||||
|
||||
### Float Button Group Props
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| width | `number \| string` | `40` | The width |
|
||||
| height | `number \| string` | `40` | The height |
|
||||
| left | `number \| string` | `40` | The width from the left side of the page |
|
||||
| right | `number \| string` | `40` | The width from the right side of the page |
|
||||
| top | `number \| string` | `40` | The height from the top of the page |
|
||||
| bottom | `number \| string` | `40` | The height from the bottom of the page |
|
||||
| radius | `number \| string` | `22` | The radius |
|
||||
| background-color | `string` | `undefined` | Background color. |
|
||||
| vertical | `boolean` | `undefined` | The direction of the child elements |
|
29
src/float-button/demos/enUS/tooltip.demo.vue
Normal file
29
src/float-button/demos/enUS/tooltip.demo.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<markdown>
|
||||
# Tooltip
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<div style="height: 200px; transform: translate(0)">
|
||||
<n-tooltip trigger="hover" placement="left">
|
||||
<template #trigger>
|
||||
<n-float-button :right="0" :bottom="0">
|
||||
<n-icon :size="24">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-float-button>
|
||||
</template>
|
||||
This story is not over.
|
||||
</n-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
CashIcon
|
||||
}
|
||||
})
|
||||
</script>
|
64
src/float-button/demos/zhCN/badge.demo.vue
Normal file
64
src/float-button/demos/zhCN/badge.demo.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<markdown>
|
||||
# 徽章
|
||||
|
||||
带有徽章数的悬浮按钮
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<div style="height: 200px; transform: translate(0)">
|
||||
<n-float-button :right="0" :bottom="0">
|
||||
<n-badge :value="9" :offset="[6, -8]">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
<n-float-button :right="70" :bottom="0">
|
||||
<n-badge :value="100" :max="99" :offset="[6, -8]">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
<n-float-button :right="142" :bottom="0">
|
||||
<n-badge dot :offset="[4, -4]">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
<n-float-button :right="142" :bottom="0">
|
||||
<n-badge dot :offset="[4, -4]">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
<n-float-button :right="0" :bottom="60">
|
||||
<n-badge value="新" :offset="[6, -6]">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
<n-float-button :right="70" :bottom="60">
|
||||
<n-badge :value="9" :offset="[6, -8]" color="grey">
|
||||
<n-icon :size="22" color="grey">
|
||||
<alarm-outline-icon />
|
||||
</n-icon>
|
||||
</n-badge>
|
||||
</n-float-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { AlarmOutline as AlarmOutlineIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
AlarmOutlineIcon
|
||||
}
|
||||
})
|
||||
</script>
|
39
src/float-button/demos/zhCN/basic.demo.vue
Normal file
39
src/float-button/demos/zhCN/basic.demo.vue
Normal file
@ -0,0 +1,39 @@
|
||||
<markdown>
|
||||
# 基础用法
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<div style="height: 200px; transform: translate(0)">
|
||||
<n-float-button :right="0" :bottom="0">
|
||||
<n-icon :size="24">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-float-button>
|
||||
<n-float-button :left="0" :bottom="0">
|
||||
<n-icon :size="24">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-float-button>
|
||||
<n-float-button :right="0" :top="0">
|
||||
<n-icon :size="24">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-float-button>
|
||||
<n-float-button :left="0" :top="0">
|
||||
<n-icon :size="24">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-float-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
CashIcon
|
||||
}
|
||||
})
|
||||
</script>
|
49
src/float-button/demos/zhCN/custom.demo.vue
Normal file
49
src/float-button/demos/zhCN/custom.demo.vue
Normal file
@ -0,0 +1,49 @@
|
||||
<markdown>
|
||||
# 自定义元素
|
||||
|
||||
可以放任意元素
|
||||
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<div style="height: 200px; transform: translate(0)">
|
||||
<n-float-button
|
||||
:right="0"
|
||||
:bottom="60"
|
||||
height="auto"
|
||||
width="auto"
|
||||
:radius="10"
|
||||
>
|
||||
<n-flex
|
||||
vertical
|
||||
:style="{ padding: '4px', textAlign: 'center' }"
|
||||
align="center"
|
||||
>
|
||||
<n-icon :size="24">
|
||||
<document-icon />
|
||||
</n-icon>
|
||||
<span> 文档 </span>
|
||||
</n-flex>
|
||||
</n-float-button>
|
||||
|
||||
<n-float-button :right="0" :left="0" :bottom="0" width="100%" :radius="10">
|
||||
<n-flex align="center">
|
||||
<n-icon :size="24">
|
||||
<document-icon />
|
||||
</n-icon>
|
||||
<span> 文档 </span>
|
||||
</n-flex>
|
||||
</n-float-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { Document as DocumentIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
DocumentIcon
|
||||
}
|
||||
})
|
||||
</script>
|
80
src/float-button/demos/zhCN/group.demo.vue
Normal file
80
src/float-button/demos/zhCN/group.demo.vue
Normal file
@ -0,0 +1,80 @@
|
||||
<markdown>
|
||||
# 浮动按钮组
|
||||
|
||||
可以任意组合元素,实现更多的功能。
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<div style="height: 200px; transform: translate(0)">
|
||||
<n-float-button-group
|
||||
:left="0"
|
||||
right="auto"
|
||||
:bottom="0"
|
||||
vertical
|
||||
background-color="lightgrey"
|
||||
>
|
||||
<n-button
|
||||
tertiary
|
||||
circle
|
||||
type="primary"
|
||||
:style="{ marginBottom: '20px' }"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button tertiary circle type="info" :style="{ marginBottom: '20px' }">
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button
|
||||
tertiary
|
||||
circle
|
||||
type="success"
|
||||
:style="{ marginBottom: '20px' }"
|
||||
>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</n-button>
|
||||
<n-button tertiary circle type="warning">
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
</n-float-button-group>
|
||||
|
||||
<n-float-button-group :right="0" :bottom="0">
|
||||
<n-flex vertical>
|
||||
<n-button tertiary circle type="primary">
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button tertiary circle type="info">
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
<n-button tertiary circle type="success">
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</n-button>
|
||||
<n-button tertiary circle type="warning">
|
||||
<template #icon>
|
||||
<n-icon><cash-icon /></n-icon>
|
||||
</template>
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</n-float-button-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
CashIcon
|
||||
}
|
||||
})
|
||||
</script>
|
44
src/float-button/demos/zhCN/index.demo-entry.md
Normal file
44
src/float-button/demos/zhCN/index.demo-entry.md
Normal file
@ -0,0 +1,44 @@
|
||||
# 浮动按钮 Float Button
|
||||
|
||||
跟 `Back Top` 很像,多一份颜值,多一份互动。
|
||||
|
||||
`NEXT_VERSION` 版本开始提供该组件。
|
||||
|
||||
## 演示
|
||||
|
||||
```demo
|
||||
basic.vue
|
||||
badge.vue
|
||||
tooltip.vue
|
||||
custom.vue
|
||||
group.vue
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### Float Button Props
|
||||
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| ---------------- | ------------------ | --------- | ------------------ |
|
||||
| width | `number \| string` | `40` | 宽度 |
|
||||
| height | `number \| string` | `40` | 高度 |
|
||||
| left | `number \| string` | `40` | 距离页面左侧的宽度 |
|
||||
| right | `number \| string` | `40` | 距离页面右侧的宽度 |
|
||||
| top | `number \| string` | `40` | 距离页面顶部的高度 |
|
||||
| bottom | `number \| string` | `40` | 距离页面底部的高度 |
|
||||
| radius | `number \| string` | `22` | 圆角 |
|
||||
| background-color | `string` | `#ffffff` | 背景色 |
|
||||
|
||||
### Float Button Group Props
|
||||
|
||||
| 名称 | 类型 | 默认值 | 说明 |
|
||||
| ---------------- | ------------------ | ----------- | ------------------ |
|
||||
| width | `number \| string` | `40` | 宽度 |
|
||||
| height | `number \| string` | `40` | 高度 |
|
||||
| left | `number \| string` | `40` | 距离页面左侧的宽度 |
|
||||
| right | `number \| string` | `40` | 距离页面右侧的宽度 |
|
||||
| top | `number \| string` | `40` | 距离页面顶部的高度 |
|
||||
| bottom | `number \| string` | `40` | 距离页面底部的高度 |
|
||||
| radius | `number \| string` | `22` | 圆角 |
|
||||
| background-color | `string` | `undefined` | 背景色 |
|
||||
| vertical | `boolean` | `undefined` | 子元素排列的方向 |
|
29
src/float-button/demos/zhCN/tooltip.demo.vue
Normal file
29
src/float-button/demos/zhCN/tooltip.demo.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<markdown>
|
||||
# 气泡提示
|
||||
</markdown>
|
||||
|
||||
<template>
|
||||
<div style="height: 200px; transform: translate(0)">
|
||||
<n-tooltip trigger="hover" placement="left">
|
||||
<template #trigger>
|
||||
<n-float-button :right="0" :bottom="0">
|
||||
<n-icon :size="24">
|
||||
<cash-icon />
|
||||
</n-icon>
|
||||
</n-float-button>
|
||||
</template>
|
||||
这个故事还没有完结
|
||||
</n-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { CashOutline as CashIcon } from '@vicons/ionicons5'
|
||||
import { defineComponent } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
CashIcon
|
||||
}
|
||||
})
|
||||
</script>
|
2
src/float-button/index.ts
Normal file
2
src/float-button/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export { default as NFloatButton, floatButtonProps } from './src/FloatButton'
|
||||
export type { FloatButtonProps } from './src/FloatButton'
|
116
src/float-button/src/FloatButton.tsx
Normal file
116
src/float-button/src/FloatButton.tsx
Normal file
@ -0,0 +1,116 @@
|
||||
import {
|
||||
h,
|
||||
defineComponent,
|
||||
type PropType,
|
||||
computed,
|
||||
type CSSProperties
|
||||
} from 'vue'
|
||||
import { type ExtractPublicPropTypes } from '../../_utils'
|
||||
import useConfig from '../../_mixins/use-config'
|
||||
import style from './styles/index.cssr'
|
||||
import { type ThemeProps, useTheme } from '../../_mixins'
|
||||
import { type FloatButtonTheme, floatButtonLight } from '../styles'
|
||||
|
||||
export const floatButtonProps = {
|
||||
...(useTheme.props as ThemeProps<FloatButtonTheme>),
|
||||
width: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: 40
|
||||
},
|
||||
height: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: 40
|
||||
},
|
||||
left: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: undefined
|
||||
},
|
||||
right: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: 40
|
||||
},
|
||||
top: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: undefined
|
||||
},
|
||||
bottom: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: 40
|
||||
},
|
||||
radius: {
|
||||
type: [Number, String] as PropType<string | number>,
|
||||
default: 22
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: '#ffffff'
|
||||
}
|
||||
} as const
|
||||
|
||||
export type FloatButtonProps = ExtractPublicPropTypes<typeof floatButtonProps>
|
||||
|
||||
export default defineComponent({
|
||||
name: 'FloatButton',
|
||||
props: floatButtonProps,
|
||||
setup (props) {
|
||||
const { mergedClsPrefixRef, inlineThemeDisabled } = useConfig(props)
|
||||
|
||||
const themeRef = useTheme(
|
||||
'FloatButton',
|
||||
'-float-button',
|
||||
style,
|
||||
floatButtonLight,
|
||||
props,
|
||||
mergedClsPrefixRef
|
||||
)
|
||||
|
||||
const cssVarsRef = computed(() => {
|
||||
const {
|
||||
self: { color, textColor, boxShadow, boxShadowHover, boxShadowPressed },
|
||||
common: { cubicBezierEaseInOut }
|
||||
} = themeRef.value
|
||||
return {
|
||||
'--n-bezier': cubicBezierEaseInOut,
|
||||
'--n-box-shadow': boxShadow,
|
||||
'--n-box-shadow-hover': boxShadowHover,
|
||||
'--n-box-shadow-pressed': boxShadowPressed,
|
||||
'--n-color': color,
|
||||
'--n-text-color': textColor,
|
||||
left: formatNumber(props.left),
|
||||
right: formatNumber(props.right),
|
||||
top: formatNumber(props.top),
|
||||
bottom: formatNumber(props.bottom),
|
||||
width: formatNumber(props.width),
|
||||
height: formatNumber(props.height),
|
||||
borderRadius: formatNumber(props.radius),
|
||||
backgroundColor: props.backgroundColor
|
||||
}
|
||||
})
|
||||
|
||||
const formatNumber = (
|
||||
value: number | string | undefined
|
||||
): string | undefined => {
|
||||
if (typeof value === 'number') return `${value}px`
|
||||
return value
|
||||
}
|
||||
|
||||
return {
|
||||
cssVars: inlineThemeDisabled ? undefined : cssVarsRef,
|
||||
mergedClsPrefix: mergedClsPrefixRef,
|
||||
formatNumber
|
||||
}
|
||||
},
|
||||
|
||||
render () {
|
||||
const { mergedClsPrefix, cssVars, $slots } = this
|
||||
|
||||
return (
|
||||
<div
|
||||
class={`${mergedClsPrefix}-float-button`}
|
||||
style={cssVars as CSSProperties}
|
||||
>
|
||||
{$slots.default?.()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
30
src/float-button/src/styles/index.cssr.ts
Normal file
30
src/float-button/src/styles/index.cssr.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { c, cB } from '../../../_utils/cssr'
|
||||
|
||||
// vars:
|
||||
// --n-bezier
|
||||
// --n-box-shadow
|
||||
// --n-box-shadow-hover
|
||||
// --n-box-shadow-pressed
|
||||
// --n-color
|
||||
// --n-text-color
|
||||
|
||||
export default cB('float-button', `
|
||||
position: fixed;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: var(--n-text-color);
|
||||
transition:
|
||||
color .3s var(--n-bezier),
|
||||
box-shadow .3s var(--n-bezier),
|
||||
background-color .3s var(--n-bezier);
|
||||
box-shadow: var(--n-box-shadow);
|
||||
`, [
|
||||
c('&:hover', {
|
||||
boxShadow: 'var(--n-box-shadow-hover)'
|
||||
}),
|
||||
c('&:active', {
|
||||
boxShadow: 'var(--n-box-shadow-pressed)'
|
||||
})
|
||||
])
|
19
src/float-button/styles/dark.ts
Normal file
19
src/float-button/styles/dark.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { commonDark } from '../../_styles/common'
|
||||
import type { FloatButtonTheme } from './light'
|
||||
|
||||
const floatButtonDark: FloatButtonTheme = {
|
||||
name: 'FloatButton',
|
||||
common: commonDark,
|
||||
self (vars) {
|
||||
const { popoverColor, textColor2 } = vars
|
||||
return {
|
||||
color: popoverColor,
|
||||
textColor: textColor2,
|
||||
boxShadow: '0 2px 8px 0px rgba(0, 0, 0, .12)',
|
||||
boxShadowHover: '0 2px 12px 0px rgba(0, 0, 0, .18)',
|
||||
boxShadowPressed: '0 2px 12px 0px rgba(0, 0, 0, .18)'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default floatButtonDark
|
3
src/float-button/styles/index.ts
Normal file
3
src/float-button/styles/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export { default as floatButtonDark } from './dark'
|
||||
export { default as floatButtonLight } from './light'
|
||||
export type { FloatButtonTheme, FloatButtonThemeVars } from './light'
|
25
src/float-button/styles/light.ts
Normal file
25
src/float-button/styles/light.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { commonLight } from '../../_styles/common'
|
||||
import type { ThemeCommonVars } from '../../_styles/common'
|
||||
import { type Theme } from '../../_mixins'
|
||||
|
||||
const self = (vars: ThemeCommonVars) => {
|
||||
const { popoverColor, textColor2 } = vars
|
||||
return {
|
||||
color: popoverColor,
|
||||
textColor: textColor2,
|
||||
boxShadow: '0 2px 8px 0px rgba(0, 0, 0, .12)',
|
||||
boxShadowHover: '0 2px 12px 0px rgba(0, 0, 0, .18)',
|
||||
boxShadowPressed: '0 2px 12px 0px rgba(0, 0, 0, .18)'
|
||||
}
|
||||
}
|
||||
|
||||
export type FloatButtonThemeVars = ReturnType<typeof self>
|
||||
|
||||
const themeLight: Theme<'FloatButton', FloatButtonThemeVars> = {
|
||||
name: 'FloatButton',
|
||||
common: commonLight,
|
||||
self
|
||||
}
|
||||
|
||||
export default themeLight
|
||||
export type FloatButtonTheme = typeof themeLight
|
@ -32,6 +32,7 @@ import { ellipsisDark } from '../ellipsis/styles'
|
||||
import { emptyDark } from '../empty/styles'
|
||||
import { equationDark } from '../equation/styles'
|
||||
import { formDark } from '../form/styles'
|
||||
import { floatButtonDark } from '../float-button/styles'
|
||||
import { gradientTextDark } from '../gradient-text/styles'
|
||||
import { iconDark } from '../icon/styles'
|
||||
import { iconWrapperDark } from '../icon-wrapper/styles'
|
||||
@ -84,6 +85,7 @@ import { watermarkDark } from '../watermark/styles'
|
||||
import { splitDark } from '../split/styles'
|
||||
import type { BuiltInGlobalTheme } from './interface'
|
||||
import { flexDark } from '../styles'
|
||||
import { floatButtonGroupDark } from '../float-button-group/styles'
|
||||
|
||||
export const darkTheme: BuiltInGlobalTheme = {
|
||||
name: 'dark',
|
||||
@ -171,5 +173,7 @@ export const darkTheme: BuiltInGlobalTheme = {
|
||||
Typography: typographyDark,
|
||||
Upload: uploadDark,
|
||||
Watermark: watermarkDark,
|
||||
Split: splitDark
|
||||
Split: splitDark,
|
||||
FloatButton: floatButtonDark,
|
||||
FloatButtonGroup: floatButtonGroupDark
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ import { ellipsisLight } from '../ellipsis/styles'
|
||||
import { emptyLight } from '../empty/styles'
|
||||
import { equationLight } from '../equation/styles'
|
||||
import { formLight } from '../form/styles'
|
||||
import { floatButtonLight } from '../float-button/styles'
|
||||
import { gradientTextLight } from '../gradient-text/styles'
|
||||
import { iconLight } from '../icon/styles'
|
||||
import { iconWrapperLight } from '../icon-wrapper/styles'
|
||||
@ -86,6 +87,7 @@ import { watermarkLight } from '../watermark/styles'
|
||||
import { splitLight } from '../split/styles'
|
||||
import type { BuiltInGlobalTheme } from './interface'
|
||||
import { flexLight } from '../flex/styles'
|
||||
import { floatButtonGroupLight } from '../float-button-group/styles'
|
||||
|
||||
export const lightTheme: BuiltInGlobalTheme = {
|
||||
name: 'light',
|
||||
@ -173,5 +175,7 @@ export const lightTheme: BuiltInGlobalTheme = {
|
||||
Typography: typographyLight,
|
||||
Upload: uploadLight,
|
||||
Watermark: watermarkLight,
|
||||
Split: splitLight
|
||||
Split: splitLight,
|
||||
FloatButton: floatButtonLight,
|
||||
FloatButtonGroup: floatButtonGroupLight
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user