little-dizzy 2.2.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,170 @@
1
+ <template>
2
+ <div class="Lztext-wrapper">
3
+ <div class="loader-wrapper">
4
+ <span class="loader-letter">G</span>
5
+ <span class="loader-letter">e</span>
6
+ <span class="loader-letter">n</span>
7
+ <span class="loader-letter">e</span>
8
+ <span class="loader-letter">r</span>
9
+ <span class="loader-letter">a</span>
10
+ <span class="loader-letter">t</span>
11
+ <span class="loader-letter">i</span>
12
+ <span class="loader-letter">n</span>
13
+ <span class="loader-letter">g</span>
14
+ <div class="loader"></div>
15
+ </div>
16
+ </div>
17
+ </template>
18
+
19
+ <script setup>
20
+ /**
21
+ * 渐变文字动画
22
+ *
23
+ * 由 LittleDizzy Demo 自动生成
24
+ * @component Lztext
25
+ */
26
+ defineOptions({
27
+ name: 'Lztext'
28
+ })
29
+
30
+ </script>
31
+
32
+ <style scoped>
33
+ .loader-wrapper {
34
+ position: relative;
35
+ display: flex;
36
+ align-items: center;
37
+ justify-content: center;
38
+ height: 120px;
39
+ width: auto;
40
+ margin: 2rem;
41
+
42
+ font-family: "Poppins", sans-serif;
43
+ font-size: 1.6em;
44
+ font-weight: 600;
45
+ user-select: none;
46
+ color: #fff;
47
+
48
+ scale: 2;
49
+ }
50
+
51
+ .loader {
52
+ position: absolute;
53
+ top: 0;
54
+ left: 0;
55
+ height: 100%;
56
+ width: 100%;
57
+ z-index: 1;
58
+
59
+ background-color: transparent;
60
+ mask: repeating-linear-gradient(
61
+ 90deg,
62
+ transparent 0,
63
+ transparent 6px,
64
+ black 7px,
65
+ black 8px
66
+ );
67
+ }
68
+
69
+ .loader::after {
70
+ content: "";
71
+ position: absolute;
72
+ top: 0;
73
+ left: 0;
74
+ width: 100%;
75
+ height: 100%;
76
+
77
+ background-image: radial-gradient(circle at 50% 50%, #ff0 0%, transparent 50%),
78
+ radial-gradient(circle at 45% 45%, #f00 0%, transparent 45%),
79
+ radial-gradient(circle at 55% 55%, #0ff 0%, transparent 45%),
80
+ radial-gradient(circle at 45% 55%, #0f0 0%, transparent 45%),
81
+ radial-gradient(circle at 55% 45%, #00f 0%, transparent 45%);
82
+ mask: radial-gradient(
83
+ circle at 50% 50%,
84
+ transparent 0%,
85
+ transparent 10%,
86
+ black 25%
87
+ );
88
+ animation:
89
+ transform-animation 2s infinite alternate,
90
+ opacity-animation 4s infinite;
91
+ animation-timing-function: cubic-bezier(0.6, 0.8, 0.5, 1);
92
+ }
93
+
94
+ @keyframes transform-animation {
95
+ 0% {
96
+ transform: translate(-55%);
97
+ }
98
+ 100% {
99
+ transform: translate(55%);
100
+ }
101
+ }
102
+
103
+ @keyframes opacity-animation {
104
+ 0%,
105
+ 100% {
106
+ opacity: 0;
107
+ }
108
+ 15% {
109
+ opacity: 1;
110
+ }
111
+ 65% {
112
+ opacity: 0;
113
+ }
114
+ }
115
+
116
+ .loader-letter {
117
+ display: inline-block;
118
+ opacity: 0;
119
+ animation: loader-letter-anim 4s infinite linear;
120
+ z-index: 2;
121
+ }
122
+
123
+ .loader-letter:nth-child(1) {
124
+ animation-delay: 0.1s;
125
+ }
126
+ .loader-letter:nth-child(2) {
127
+ animation-delay: 0.205s;
128
+ }
129
+ .loader-letter:nth-child(3) {
130
+ animation-delay: 0.31s;
131
+ }
132
+ .loader-letter:nth-child(4) {
133
+ animation-delay: 0.415s;
134
+ }
135
+ .loader-letter:nth-child(5) {
136
+ animation-delay: 0.521s;
137
+ }
138
+ .loader-letter:nth-child(6) {
139
+ animation-delay: 0.626s;
140
+ }
141
+ .loader-letter:nth-child(7) {
142
+ animation-delay: 0.731s;
143
+ }
144
+ .loader-letter:nth-child(8) {
145
+ animation-delay: 0.837s;
146
+ }
147
+ .loader-letter:nth-child(9) {
148
+ animation-delay: 0.942s;
149
+ }
150
+ .loader-letter:nth-child(10) {
151
+ animation-delay: 1.047s;
152
+ }
153
+
154
+ @keyframes loader-letter-anim {
155
+ 0% {
156
+ opacity: 0;
157
+ }
158
+ 5% {
159
+ opacity: 1;
160
+ text-shadow: 0 0 4px #fff;
161
+ transform: scale(1.1) translateY(-2px);
162
+ }
163
+ 20% {
164
+ opacity: 0.2;
165
+ }
166
+ 100% {
167
+ opacity: 0;
168
+ }
169
+ }
170
+ </style>
@@ -6,15 +6,17 @@
6
6
  */
7
7
 
8
8
  import Lzbutton from './lzbutton.vue'
9
+ import Lztext from './Lztext.vue'
9
10
  import Lztheme from './lztheme.vue'
10
11
 
11
12
  // 自定义组件导出
12
13
  export const customComponents = {
13
14
  Lzbutton,
15
+ Lztext,
14
16
  Lztheme
15
17
  }
16
18
 
17
19
  // 单独导出每个组件
18
- export { Lzbutton, Lztheme }
20
+ export { Lzbutton, Lztext, Lztheme }
19
21
 
20
22
  export default customComponents
@@ -1,10 +1,10 @@
1
1
  <template>
2
2
  <div class="lzbutton-wrapper">
3
3
  <button class="button">
4
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 24">
5
- <path d="m18 0 8 12 10-8-4 20H4L0 4l10 8 8-12z"></path>
6
- </svg>
7
- Unlock Pro
4
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 24">
5
+ <path d="m18 0 8 12 10-8-4 20H4L0 4l10 8 8-12z"></path>
6
+ </svg>
7
+ <slot>Unlock Pro</slot>
8
8
  </button>
9
9
  </div>
10
10
  </template>
@@ -36,7 +36,7 @@ defineOptions({
36
36
  color: #fff;
37
37
  border: none;
38
38
  background-position: left center;
39
- box-shadow: 0 30px 10px -20px rgba(0,0,0,.2);
39
+ box-shadow: 0 30px 10px -20px rgba(0, 0, 0, .2);
40
40
  transition: background .3s ease;
41
41
  }
42
42
 
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Message 全局消息提示服务
3
+ *
4
+ * 使用方法:
5
+ * import { message } from '@/components/message.js'
6
+ *
7
+ * message.success('操作成功')
8
+ * message.error('操作失败')
9
+ * message.warning('警告信息')
10
+ * message.info('提示信息')
11
+ *
12
+ * // 带配置
13
+ * message.success('操作成功', { duration: 5000, closable: true })
14
+ */
15
+
16
+ import { createApp, h, ref } from 'vue'
17
+ import Message from './Message.vue'
18
+
19
+ let messageInstance = null
20
+ let messageContainer = null
21
+
22
+ // Initialize message instance
23
+ const initMessage = () => {
24
+ if (messageInstance) return messageInstance
25
+
26
+ messageContainer = document.createElement('div')
27
+ messageContainer.id = 'ld-message-container'
28
+ document.body.appendChild(messageContainer)
29
+
30
+ const app = createApp({
31
+ setup () {
32
+ const messageRef = ref(null)
33
+ return () => h(Message, { ref: messageRef })
34
+ }
35
+ })
36
+
37
+ const vm = app.mount(messageContainer)
38
+ messageInstance = vm.$el.__vueParentComponent?.exposed || vm.$el.parentNode?.__vueParentComponent?.subTree?.component?.exposed
39
+
40
+ // Wait for next tick to get the exposed methods
41
+ return new Promise((resolve) => {
42
+ setTimeout(() => {
43
+ const container = document.querySelector('#ld-message-container')
44
+ if (container) {
45
+ const vueInstance = container._vnode?.component?.subTree?.component?.exposed
46
+ if (vueInstance) {
47
+ messageInstance = vueInstance
48
+ resolve(messageInstance)
49
+ }
50
+ }
51
+ }, 0)
52
+ })
53
+ }
54
+
55
+ // Create a simpler implementation using reactive state
56
+ const messages = ref([])
57
+ let messageId = 0
58
+
59
+ const typeClasses = {
60
+ success: 'ld-message--success',
61
+ warning: 'ld-message--warning',
62
+ error: 'ld-message--error',
63
+ info: 'ld-message--info'
64
+ }
65
+
66
+ const createMessageElement = (options) => {
67
+ const id = ++messageId
68
+ const type = options.type || 'info'
69
+ const content = options.content || ''
70
+ const duration = options.duration ?? 3000
71
+ const closable = options.closable ?? false
72
+
73
+ // Create message element
74
+ const msgEl = document.createElement('div')
75
+ msgEl.className = `ld-message ld-message--${type}`
76
+ msgEl.setAttribute('data-id', id)
77
+
78
+ // Icon SVGs
79
+ const icons = {
80
+ success: `<svg class="ld-message-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
81
+ <path d="M20 6L9 17l-5-5" stroke-linecap="round" stroke-linejoin="round"/>
82
+ </svg>`,
83
+ warning: `<svg class="ld-message-icon" viewBox="0 0 24 24" fill="currentColor">
84
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>
85
+ </svg>`,
86
+ error: `<svg class="ld-message-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
87
+ <circle cx="12" cy="12" r="10"/>
88
+ <path d="M15 9l-6 6M9 9l6 6" stroke-linecap="round"/>
89
+ </svg>`,
90
+ info: `<svg class="ld-message-icon" viewBox="0 0 24 24" fill="currentColor">
91
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
92
+ </svg>`
93
+ }
94
+
95
+ let html = `${icons[type]}<span class="ld-message-content">${content}</span>`
96
+
97
+ if (closable) {
98
+ html += `<button class="ld-message-close" onclick="window.__ldMessageClose(${id})">
99
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
100
+ <path d="M18 6L6 18M6 6l12 12"/>
101
+ </svg>
102
+ </button>`
103
+ }
104
+
105
+ msgEl.innerHTML = html
106
+
107
+ return { id, element: msgEl, duration }
108
+ }
109
+
110
+ // Ensure container exists
111
+ const ensureContainer = () => {
112
+ let container = document.getElementById('ld-message-root')
113
+ if (!container) {
114
+ container = document.createElement('div')
115
+ container.id = 'ld-message-root'
116
+ document.body.appendChild(container)
117
+
118
+ // Add styles
119
+ const style = document.createElement('style')
120
+ style.textContent = `
121
+ #ld-message-root {
122
+ position: fixed;
123
+ top: 16px;
124
+ left: 50%;
125
+ transform: translateX(-50%);
126
+ z-index: 9999;
127
+ display: flex;
128
+ flex-direction: column;
129
+ align-items: center;
130
+ gap: 12px;
131
+ pointer-events: none;
132
+ }
133
+ .ld-message {
134
+ pointer-events: auto;
135
+ display: flex;
136
+ align-items: center;
137
+ gap: 12px;
138
+ padding: 12px 20px;
139
+ border-radius: 8px;
140
+ box-shadow: 0 4px 12px rgba(0,0,0,0.15);
141
+ backdrop-filter: blur(8px);
142
+ animation: ldMessageIn 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
143
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
144
+ font-size: 14px;
145
+ font-weight: 500;
146
+ }
147
+ .ld-message.ld-message--closing {
148
+ animation: ldMessageOut 0.2s ease-in forwards;
149
+ }
150
+ .ld-message--success { background: rgba(16, 185, 129, 0.95); color: white; }
151
+ .ld-message--warning { background: rgba(245, 158, 11, 0.95); color: white; }
152
+ .ld-message--error { background: rgba(239, 68, 68, 0.95); color: white; }
153
+ .ld-message--info { background: rgba(14, 165, 233, 0.95); color: white; }
154
+ .ld-message-icon { width: 20px; height: 20px; flex-shrink: 0; }
155
+ .ld-message-content { white-space: nowrap; }
156
+ .ld-message-close {
157
+ display: flex;
158
+ align-items: center;
159
+ justify-content: center;
160
+ width: 20px;
161
+ height: 20px;
162
+ margin-left: 4px;
163
+ padding: 0;
164
+ border: none;
165
+ background: transparent;
166
+ color: currentColor;
167
+ cursor: pointer;
168
+ border-radius: 50%;
169
+ transition: background 0.2s;
170
+ }
171
+ .ld-message-close:hover { background: rgba(255,255,255,0.2); }
172
+ .ld-message-close svg { width: 14px; height: 14px; }
173
+ @keyframes ldMessageIn {
174
+ from { opacity: 0; transform: translateY(-20px) scale(0.9); }
175
+ to { opacity: 1; transform: translateY(0) scale(1); }
176
+ }
177
+ @keyframes ldMessageOut {
178
+ from { opacity: 1; transform: translateY(0) scale(1); }
179
+ to { opacity: 0; transform: translateY(-10px) scale(0.95); }
180
+ }
181
+ `
182
+ document.head.appendChild(style)
183
+ }
184
+ return container
185
+ }
186
+
187
+ // Close message
188
+ const closeMessage = (id) => {
189
+ const container = document.getElementById('ld-message-root')
190
+ if (!container) return
191
+
192
+ const msgEl = container.querySelector(`[data-id="${id}"]`)
193
+ if (msgEl) {
194
+ msgEl.classList.add('ld-message--closing')
195
+ setTimeout(() => {
196
+ msgEl.remove()
197
+ }, 200)
198
+ }
199
+ }
200
+
201
+ // Expose close function globally
202
+ if (typeof window !== 'undefined') {
203
+ window.__ldMessageClose = closeMessage
204
+ }
205
+
206
+ // Show message
207
+ const showMessage = (options) => {
208
+ const container = ensureContainer()
209
+ const { id, element, duration } = createMessageElement(options)
210
+
211
+ container.appendChild(element)
212
+
213
+ if (duration > 0) {
214
+ setTimeout(() => {
215
+ closeMessage(id)
216
+ }, duration)
217
+ }
218
+
219
+ return id
220
+ }
221
+
222
+ // Export message API
223
+ export const message = {
224
+ success: (content, options = {}) => showMessage({ ...options, type: 'success', content }),
225
+ warning: (content, options = {}) => showMessage({ ...options, type: 'warning', content }),
226
+ error: (content, options = {}) => showMessage({ ...options, type: 'error', content }),
227
+ info: (content, options = {}) => showMessage({ ...options, type: 'info', content }),
228
+ close: closeMessage,
229
+ closeAll: () => {
230
+ const container = document.getElementById('ld-message-root')
231
+ if (container) {
232
+ container.innerHTML = ''
233
+ }
234
+ }
235
+ }
236
+
237
+ export default message
238
+
package/src/index.js CHANGED
@@ -23,6 +23,8 @@
23
23
  import Button from './components/Button.vue'
24
24
  import Card from './components/Card.vue'
25
25
  import Modal from './components/Modal.vue'
26
+ import Message from './components/Message.vue'
27
+ import { message } from './components/message.js'
26
28
 
27
29
  // 导入自定义组件(由 Demo 上传生成)
28
30
  import { customComponents } from './components/custom/index.js'
@@ -35,6 +37,7 @@ const components = {
35
37
  Button,
36
38
  Card,
37
39
  Modal,
40
+ Message,
38
41
  ...customComponents
39
42
  }
40
43
 
@@ -53,7 +56,7 @@ export const registerSnippets = snippetsModule.registerSnippets
53
56
  export const getSnippet = snippetsModule.getSnippet
54
57
 
55
58
  // 导出内置组件(按需引入)
56
- export { Button, Card, Modal }
59
+ export { Button, Card, Modal, Message, message }
57
60
 
58
61
  // 重新导出自定义组件
59
62
  export * from './components/custom/index.js'
@@ -7,16 +7,18 @@
7
7
  import buttonSnippet from './button.js'
8
8
  import cardSnippet from './card.js'
9
9
  import modalSnippet from './modal.js'
10
+ import messageSnippet from './message.js'
10
11
 
11
12
  // 所有预设代码片段
12
13
  export const presetSnippets = [
13
14
  buttonSnippet,
14
15
  cardSnippet,
15
- modalSnippet
16
+ modalSnippet,
17
+ messageSnippet
16
18
  ]
17
19
 
18
20
  // 单独导出
19
- export { buttonSnippet, cardSnippet, modalSnippet }
21
+ export { buttonSnippet, cardSnippet, modalSnippet, messageSnippet }
20
22
 
21
23
  export default presetSnippets
22
24
 
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Message 消息提示组件示例代码
3
+ */
4
+ export default {
5
+ name: 'Message',
6
+ type: 'vue',
7
+ label: 'Message 消息提示',
8
+ code: `<template>
9
+ <div class="message-demo">
10
+ <Button type="success" @click="showSuccess">成功提示</Button>
11
+ <Button type="warning" @click="showWarning">警告提示</Button>
12
+ <Button type="danger" @click="showError">错误提示</Button>
13
+ <Button type="info" @click="showInfo">信息提示</Button>
14
+ </div>
15
+ </template>
16
+
17
+ <script setup>
18
+ import { Button, message } from 'little-dizzy'
19
+
20
+ const showSuccess = () => {
21
+ message.success('操作成功!')
22
+ }
23
+
24
+ const showWarning = () => {
25
+ message.warning('请注意!')
26
+ }
27
+
28
+ const showError = () => {
29
+ message.error('操作失败!')
30
+ }
31
+
32
+ const showInfo = () => {
33
+ message.info('这是一条提示信息', { duration: 5000, closable: true })
34
+ }
35
+ </script>
36
+
37
+ <style scoped>
38
+ .message-demo {
39
+ display: flex;
40
+ gap: 12px;
41
+ flex-wrap: wrap;
42
+ }
43
+ </style>`
44
+ }
45
+
@@ -34,6 +34,14 @@ $shadow-lg: 0 6px 20px rgba(0, 0, 0, 0.2);
34
34
  margin: 0;
35
35
  padding: 0;
36
36
  box-sizing: border-box;
37
+
38
+ // 隐藏滚动条(保持滚动功能)
39
+ scrollbar-width: none; // Firefox
40
+ -ms-overflow-style: none; // IE/Edge
41
+
42
+ &::-webkit-scrollbar {
43
+ display: none; // Chrome/Safari/Opera
44
+ }
37
45
  }
38
46
 
39
47
  body {
@@ -0,0 +1 @@
1
+ @import "tailwindcss";