mirror of
https://github.com/HoshinoSuzumi/rayine-ui.git
synced 2025-04-07 12:48:50 +08:00
✨ feat(mark): new component RayMark
This commit is contained in:
parent
83f8593391
commit
ddff1ca9c0
83
docs/content/2.components/mark.md
Normal file
83
docs/content/2.components/mark.md
Normal file
@ -0,0 +1,83 @@
|
||||
---
|
||||
description: Display a indicator with or without counts on any component
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
Use the default slot to add any component you want to display the indicator on.
|
||||
|
||||
::ComponentPreview
|
||||
---
|
||||
slots:
|
||||
default: |
|
||||
<RayButton icon="tabler:message" label="messages" color="invert" />
|
||||
---
|
||||
#default
|
||||
:RayButton{icon="tabler:message" label="messages" color="invert"}
|
||||
::
|
||||
|
||||
### Styles
|
||||
|
||||
You can change the color and size of the indicator by using the `color` and `size` props.
|
||||
|
||||
::ComponentPreview
|
||||
---
|
||||
props:
|
||||
color: amber
|
||||
size: sm
|
||||
slots:
|
||||
default: |
|
||||
<RayButton icon="tabler:message" label="messages" color="invert" />
|
||||
---
|
||||
#default
|
||||
:RayButton{icon="tabler:message" label="messages" color="invert"}
|
||||
::
|
||||
|
||||
### Position
|
||||
|
||||
Use the `position` prop to change the position of the indicator.
|
||||
|
||||
::ComponentPreview
|
||||
---
|
||||
props:
|
||||
position: top-right
|
||||
slots:
|
||||
default: |
|
||||
<RayButton icon="tabler:message" label="messages" color="invert" />
|
||||
---
|
||||
#default
|
||||
:RayButton{icon="tabler:message" label="messages" color="invert"}
|
||||
::
|
||||
|
||||
### Count
|
||||
|
||||
Add a count to the indicator by using the `value` prop.
|
||||
|
||||
::ComponentPreview
|
||||
---
|
||||
props:
|
||||
value: 5
|
||||
slots:
|
||||
default: |
|
||||
<RayButton icon="tabler:message" label="messages" color="invert" />
|
||||
---
|
||||
#default
|
||||
:RayButton{icon="tabler:message" label="messages" color="invert"}
|
||||
::
|
||||
|
||||
#### Overflow
|
||||
|
||||
Set `max` prop to handle overflow situation.
|
||||
|
||||
::ComponentPreview
|
||||
---
|
||||
props:
|
||||
value: 110
|
||||
max: 99
|
||||
slots:
|
||||
default: |
|
||||
<RayButton icon="tabler:message" label="messages" color="invert" />
|
||||
---
|
||||
#default
|
||||
:RayButton{icon="tabler:message" label="messages" color="invert"}
|
||||
::
|
90
src/runtime/components/elements/Mark.vue
Normal file
90
src/runtime/components/elements/Mark.vue
Normal file
@ -0,0 +1,90 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, toRef, type PropType } from 'vue'
|
||||
import { twJoin, twMerge } from 'tailwind-merge'
|
||||
import { mark } from '../../ui.config'
|
||||
import type { MarkColor, MarkPosition, MarkSize } from '../../types'
|
||||
import { useRayUI } from '#build/imports'
|
||||
|
||||
const config = mark
|
||||
|
||||
export default defineComponent({
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: {
|
||||
type: [Number, String],
|
||||
default: null,
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
size: {
|
||||
type: String as PropType<MarkSize>,
|
||||
default: config.default.size,
|
||||
},
|
||||
color: {
|
||||
type: String as PropType<MarkColor>,
|
||||
default: config.default.color,
|
||||
},
|
||||
position: {
|
||||
type: String as PropType<MarkPosition>,
|
||||
default: config.default.position,
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<typeof config>,
|
||||
default: () => ({}),
|
||||
},
|
||||
class: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { ui, attrs } = useRayUI('mark', toRef(props, 'ui'), config)
|
||||
|
||||
const markClass = computed(() => {
|
||||
return twMerge(twJoin(
|
||||
ui.value.base,
|
||||
ui.value.rounded,
|
||||
ui.value.ring,
|
||||
ui.value.position[props.position],
|
||||
ui.value.background.replaceAll('{color}', props.color),
|
||||
props.value ? ui.value.value.size[props.size] : ui.value.size[props.size],
|
||||
props.value ? ui.value.value.translate[props.position] : ui.value.translate[props.position],
|
||||
), props.class)
|
||||
})
|
||||
|
||||
const isOverMax = computed(() => {
|
||||
if (props.max === null) return false
|
||||
if (typeof props.value === 'string') return false
|
||||
return props.value > props.max
|
||||
})
|
||||
|
||||
// consider string value
|
||||
const countValue = computed(() => {
|
||||
if (typeof props.value === 'string') return props.value
|
||||
return isOverMax.value ? `${props.max}+` : props.value
|
||||
})
|
||||
|
||||
return {
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
ui,
|
||||
attrs,
|
||||
markClass,
|
||||
isOverMax,
|
||||
countValue,
|
||||
}
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="ui.wrapper">
|
||||
<span :class="markClass">
|
||||
<Transition v-bind="ui.transition">
|
||||
<span v-if="value" :key="countValue" class="leading-none">{{ countValue }}</span>
|
||||
</Transition>
|
||||
</span>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
@ -4,5 +4,6 @@ export * from './input'
|
||||
export * from './textarea'
|
||||
export * from './kbd'
|
||||
export * from './toggle'
|
||||
export * from './mark'
|
||||
|
||||
export * from './utils'
|
||||
|
14
src/runtime/types/mark.d.ts
vendored
Normal file
14
src/runtime/types/mark.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import type { mark } from '../ui.config'
|
||||
import type { ExtractDeepKey } from './utils'
|
||||
import type colors from '#ray-colors'
|
||||
|
||||
export type MarkSize =
|
||||
| keyof typeof mark.size
|
||||
| ExtractDeepKey<AppConfig, ['rayui', 'mark', 'size']>
|
||||
export type MarkColor =
|
||||
| ExtractDeepKey<AppConfig, ['rayui', 'mark', 'color']>
|
||||
| (typeof colors)[number]
|
||||
export type MarkPosition =
|
||||
| keyof typeof mark.position
|
||||
| ExtractDeepKey<AppConfig, ['rayui', 'mark', 'position']>
|
51
src/runtime/ui.config/elements/mark.ts
Normal file
51
src/runtime/ui.config/elements/mark.ts
Normal file
@ -0,0 +1,51 @@
|
||||
export default {
|
||||
wrapper: 'relative',
|
||||
base: 'absolute text-white rounded-full inline-flex justify-center items-center',
|
||||
ring: 'ring-2 ring-white dark:ring-gray-900',
|
||||
rounded: 'rounded-full',
|
||||
background: 'bg-{color}-500',
|
||||
position: {
|
||||
'top-left': 'top-0 left-0',
|
||||
'top-right': 'top-0 right-0',
|
||||
'bottom-left': 'bottom-0 left-0',
|
||||
'bottom-right': 'bottom-0 right-0',
|
||||
},
|
||||
translate: {
|
||||
'top-left': '-translate-x-0.5 -translate-y-0.5',
|
||||
'top-right': 'translate-x-0.5 -translate-y-0.5',
|
||||
'bottom-left': '-translate-x-0.5 translate-y-0.5',
|
||||
'bottom-right': 'translate-x-0.5 translate-y-0.5',
|
||||
},
|
||||
size: {
|
||||
xs: 'w-1.5 h-1.5',
|
||||
sm: 'w-2 h-2',
|
||||
md: 'w-2.5 h-2.5',
|
||||
},
|
||||
value: {
|
||||
size: {
|
||||
xs: 'px-1 h-3 leading-none text-xs',
|
||||
sm: 'px-1.5 h-4 leading-none text-xs',
|
||||
md: 'px-2 h-5 leading-none text-sm',
|
||||
},
|
||||
translate: {
|
||||
'top-left': '-translate-x-1/3 -translate-y-1/3',
|
||||
'top-right': 'translate-x-1/3 -translate-y-1/3',
|
||||
'bottom-left': '-translate-x-1/3 translate-y-1/3',
|
||||
'bottom-right': 'translate-x-1/3 translate-y-1/3',
|
||||
},
|
||||
},
|
||||
transition: {
|
||||
moveClass: 'transform ease-out duration-300 transition',
|
||||
enterActiveClass: 'transform ease-out duration-300 transition',
|
||||
leaveActiveClass: 'transform ease-out duration-300 transition absolute',
|
||||
enterFromClass: 'translate-y-2 opacity-0',
|
||||
enterToClass: 'translate-y-0 opacity-100',
|
||||
leaveFromClass: 'translate-y-0 opacity-100',
|
||||
leaveToClass: '-translate-y-2 opacity-0',
|
||||
},
|
||||
default: {
|
||||
size: 'sm',
|
||||
color: 'primary',
|
||||
position: 'top-right',
|
||||
},
|
||||
}
|
@ -4,6 +4,7 @@ export { default as standard } from './standard'
|
||||
// elements
|
||||
export { default as button } from './elements/button'
|
||||
export { default as kbd } from './elements/kbd'
|
||||
export { default as mark } from './elements/mark'
|
||||
|
||||
// forms
|
||||
export { default as input } from './forms/input'
|
||||
|
Loading…
Reference in New Issue
Block a user