mirror of
https://github.com/HoshinoSuzumi/rayine-ui.git
synced 2025-05-22 23:42:28 +08:00
🚧 wip(messages)
This commit is contained in:
parent
6d95d9f9a8
commit
f95e068bbe
@ -5,11 +5,11 @@ provide('navigation', navigation)
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<RayMessageProvider>
|
<RayMessages>
|
||||||
<NuxtLayout>
|
<NuxtLayout>
|
||||||
<NuxtPage />
|
<NuxtPage />
|
||||||
</NuxtLayout>
|
</NuxtLayout>
|
||||||
</RayMessageProvider>
|
</RayMessages>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@ -4,8 +4,6 @@ import colors from 'tailwindcss/colors'
|
|||||||
import module from '../src/module'
|
import module from '../src/module'
|
||||||
import { excludeColors } from '../src/runtime/utils/colors'
|
import { excludeColors } from '../src/runtime/utils/colors'
|
||||||
|
|
||||||
console.log(excludeColors(colors))
|
|
||||||
|
|
||||||
const { resolve } = createResolver(import.meta.url)
|
const { resolve } = createResolver(import.meta.url)
|
||||||
|
|
||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const message = useMessage()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-8">
|
<div class="flex flex-col gap-8">
|
||||||
<div
|
<div
|
||||||
class="py-20 flex flex-col justify-center items-center rounded-xl border border-neutral-200 dark:border-neutral-800 pattern"
|
class="py-20 flex flex-col justify-center items-center rounded-xl border border-neutral-200 dark:border-neutral-800 pattern">
|
||||||
>
|
|
||||||
<div class="text-xl text-neutral-600 dark:text-neutral-300 font-bold">
|
<div class="text-xl text-neutral-600 dark:text-neutral-300 font-bold">
|
||||||
<h2 class="text-xl">
|
<h2 class="text-xl">
|
||||||
RayineUI <span class="font-medium">is a multi-purpose</span>
|
RayineUI <span class="font-medium">is a multi-purpose</span>
|
||||||
@ -26,6 +26,9 @@ const router = useRouter()
|
|||||||
<RayButton variant="outline" to="/components">
|
<RayButton variant="outline" to="/components">
|
||||||
Explore Components
|
Explore Components
|
||||||
</RayButton>
|
</RayButton>
|
||||||
|
<RayButton variant="outline" @click="message.success('rayui')">
|
||||||
|
Message
|
||||||
|
</RayButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
import { ref } from 'vue'
|
|
||||||
import type { Message, MessageType } from '../../types/message'
|
|
||||||
import { useNuxtApp } from '#app'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
max: {
|
|
||||||
type: Number,
|
|
||||||
default: 5,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
const nuxtApp = useNuxtApp()
|
|
||||||
const messageList = ref<Message[]>([])
|
|
||||||
|
|
||||||
const createMessage = (content: string, type: MessageType, duration: number = 3000) => {
|
|
||||||
const { max } = props
|
|
||||||
messageList.value.push({
|
|
||||||
id: (Date.now() + Math.random() * 100).toString(32).toUpperCase(),
|
|
||||||
content,
|
|
||||||
type,
|
|
||||||
duration,
|
|
||||||
})
|
|
||||||
if (messageList.value.length > max) {
|
|
||||||
messageList.value.shift()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const providerApi = {
|
|
||||||
destroy: (id: string) => {
|
|
||||||
if (!messageList.value.find(message => message.id === id)) return
|
|
||||||
messageList.value.splice(messageList.value.findIndex(message => message.id === id), 1)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const api = {
|
|
||||||
info: (content: string, duration: number = 3000) => {
|
|
||||||
createMessage(content, 'info', duration)
|
|
||||||
},
|
|
||||||
success: (content: string, duration: number = 3000) => {
|
|
||||||
createMessage(content, 'success', duration)
|
|
||||||
},
|
|
||||||
warning: (content: string, duration: number = 3000) => {
|
|
||||||
createMessage(content, 'warning', duration)
|
|
||||||
},
|
|
||||||
error: (content: string, duration: number = 3000) => {
|
|
||||||
createMessage(content, 'error', duration)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
nuxtApp.vueApp.provide('ray-message-provider', providerApi)
|
|
||||||
nuxtApp.vueApp.provide('ray-message', api)
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<slot />
|
|
||||||
<teleport to="body">
|
|
||||||
<div id="message-provider">
|
|
||||||
<div class="message-wrapper">
|
|
||||||
<TransitionGroup name="message">
|
|
||||||
<RayMessage
|
|
||||||
v-for="(message) in messageList"
|
|
||||||
:key="message.id"
|
|
||||||
:message="message"
|
|
||||||
/>
|
|
||||||
</TransitionGroup>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</teleport>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
#message-provider .message-wrapper {
|
|
||||||
@apply z-[50000] fixed inset-0 flex flex-col items-center pointer-events-none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-move,
|
|
||||||
.message-leave-active {
|
|
||||||
transition: all .8s cubic-bezier(0.075, 0.82, 0.165, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-enter-active {
|
|
||||||
transition: all .8s cubic-bezier(0.075, 0.82, 0.165, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-enter-from {
|
|
||||||
filter: blur(2px);
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-leave-to {
|
|
||||||
filter: blur(6px);
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-20%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-leave-active {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
</style>
|
|
134
src/runtime/components/overlays/Messages.vue
Normal file
134
src/runtime/components/overlays/Messages.vue
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { computed, defineComponent, ref, toRef, type PropType } from 'vue'
|
||||||
|
import type { Message, MessageType } from '../../types/message'
|
||||||
|
import { useNuxtApp } from '#app'
|
||||||
|
import { messages } from '../../ui.config';
|
||||||
|
import { twJoin, twMerge } from 'tailwind-merge';
|
||||||
|
import { useRayUI } from '#build/imports';
|
||||||
|
import type { DeepPartial, Strategy } from '../../types';
|
||||||
|
|
||||||
|
const config = messages
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
max: {
|
||||||
|
type: Number,
|
||||||
|
default: 5,
|
||||||
|
},
|
||||||
|
class: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
ui: {
|
||||||
|
type: Object as PropType<DeepPartial<typeof config> & { strategy?: Strategy }>,
|
||||||
|
default: () => ({}),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const { ui, attrs } = useRayUI('messages', toRef(props, 'ui'), config)
|
||||||
|
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
const messageList = ref<Message[]>([])
|
||||||
|
|
||||||
|
const wrapperClass = computed(() => {
|
||||||
|
return twMerge(twJoin(
|
||||||
|
ui.value.wrapper,
|
||||||
|
ui.value.position
|
||||||
|
), props.class)
|
||||||
|
})
|
||||||
|
|
||||||
|
const createMessage = (content: string, type: MessageType, duration: number = 3000) => {
|
||||||
|
const { max } = props
|
||||||
|
messageList.value.push({
|
||||||
|
id: (Date.now() + Math.random() * 100).toString(32).toUpperCase(),
|
||||||
|
content,
|
||||||
|
type,
|
||||||
|
duration,
|
||||||
|
})
|
||||||
|
if (messageList.value.length > max) {
|
||||||
|
messageList.value.shift()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const providerApi = {
|
||||||
|
destroy: (id: string) => {
|
||||||
|
if (!messageList.value.find(message => message.id === id)) return
|
||||||
|
messageList.value.splice(messageList.value.findIndex(message => message.id === id), 1)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const api = {
|
||||||
|
info: (content: string, duration: number = 3000) => {
|
||||||
|
createMessage(content, 'info', duration)
|
||||||
|
},
|
||||||
|
success: (content: string, duration: number = 3000) => {
|
||||||
|
createMessage(content, 'success', duration)
|
||||||
|
},
|
||||||
|
warning: (content: string, duration: number = 3000) => {
|
||||||
|
createMessage(content, 'warning', duration)
|
||||||
|
},
|
||||||
|
error: (content: string, duration: number = 3000) => {
|
||||||
|
createMessage(content, 'error', duration)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
nuxtApp.vueApp.provide('ray-message-provider', providerApi)
|
||||||
|
nuxtApp.vueApp.provide('ray-message', api)
|
||||||
|
|
||||||
|
return {
|
||||||
|
ui,
|
||||||
|
attrs,
|
||||||
|
messageList,
|
||||||
|
wrapperClass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<slot></slot>
|
||||||
|
<teleport to="body">
|
||||||
|
<div :class="wrapperClass">
|
||||||
|
<div :class="ui.container">
|
||||||
|
<TransitionGroup name="message">
|
||||||
|
<RayMessage
|
||||||
|
v-for="(message) in messageList"
|
||||||
|
:key="message.id"
|
||||||
|
:message="message"
|
||||||
|
/>
|
||||||
|
</TransitionGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</teleport>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#message-provider .message-wrapper {
|
||||||
|
@apply z-[50000] fixed inset-0 flex flex-col items-center pointer-events-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-move,
|
||||||
|
.message-leave-active {
|
||||||
|
transition: all .8s cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-enter-active {
|
||||||
|
transition: all .8s cubic-bezier(0.075, 0.82, 0.165, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-enter-from {
|
||||||
|
filter: blur(2px);
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-leave-to {
|
||||||
|
filter: blur(6px);
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-leave-active {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
2
src/runtime/types/message.d.ts
vendored
2
src/runtime/types/message.d.ts
vendored
@ -7,6 +7,8 @@ export interface Message {
|
|||||||
duration?: number
|
duration?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type MessageOption = Omit<Message, 'id'>
|
||||||
|
|
||||||
export interface MessageApi {
|
export interface MessageApi {
|
||||||
info: (content: string, duration?: number) => void
|
info: (content: string, duration?: number) => void
|
||||||
success: (content: string, duration?: number) => void
|
success: (content: string, duration?: number) => void
|
||||||
|
@ -1,2 +1,6 @@
|
|||||||
// elements
|
// elements
|
||||||
export { default as button } from './elements/button'
|
export { default as button } from './elements/button'
|
||||||
|
|
||||||
|
// overlays
|
||||||
|
export { default as message } from './overlays/message'
|
||||||
|
export { default as messages } from "./overlays/messages";
|
||||||
|
1
src/runtime/ui.config/overlays/message.ts
Normal file
1
src/runtime/ui.config/overlays/message.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export default {}
|
5
src/runtime/ui.config/overlays/messages.ts
Normal file
5
src/runtime/ui.config/overlays/messages.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export default {
|
||||||
|
wrapper: "fixed flex flex-col w-full pointer-events-none z-[500]",
|
||||||
|
position: "bottom-0 end-0",
|
||||||
|
container: "px-4 sm:px-6 py-6 space-y-3 overflow-y-auto",
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user