little-dizzy 2.3.0 → 2.5.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.
@@ -1,26 +1,28 @@
1
1
  <template>
2
2
  <div class="lztheme-wrapper">
3
- <label for="theme" class="theme">
4
- <span class="theme__toggle-wrap">
5
- <input id="theme" class="theme__toggle" type="checkbox" role="switch" name="theme" value="dark">
6
- <span class="theme__fill"></span>
7
- <span class="theme__icon">
8
- <span class="theme__icon-part"></span>
9
- <span class="theme__icon-part"></span>
10
- <span class="theme__icon-part"></span>
11
- <span class="theme__icon-part"></span>
12
- <span class="theme__icon-part"></span>
13
- <span class="theme__icon-part"></span>
14
- <span class="theme__icon-part"></span>
15
- <span class="theme__icon-part"></span>
16
- <span class="theme__icon-part"></span>
17
- </span>
18
- </span>
3
+ <label :for="inputId" class="theme">
4
+ <span class="theme__toggle-wrap">
5
+ <input :id="inputId" ref="toggleRef" class="theme__toggle" type="checkbox" role="switch" name="theme"
6
+ value="dark" :checked="isDark" @change="handleChange">
7
+ <span class="theme__icon">
8
+ <span class="theme__icon-part"></span>
9
+ <span class="theme__icon-part"></span>
10
+ <span class="theme__icon-part"></span>
11
+ <span class="theme__icon-part"></span>
12
+ <span class="theme__icon-part"></span>
13
+ <span class="theme__icon-part"></span>
14
+ <span class="theme__icon-part"></span>
15
+ <span class="theme__icon-part"></span>
16
+ <span class="theme__icon-part"></span>
17
+ </span>
18
+ </span>
19
19
  </label>
20
20
  </div>
21
21
  </template>
22
22
 
23
23
  <script setup>
24
+ import { ref, watch } from 'vue'
25
+
24
26
  /**
25
27
  * 主题切换
26
28
  *
@@ -30,6 +32,53 @@
30
32
  defineOptions({
31
33
  name: 'Lztheme'
32
34
  })
35
+
36
+ // 生成唯一 ID,避免多个实例冲突
37
+ let idCounter = 0
38
+ const inputId = `lztheme-toggle-${++idCounter}-${Date.now()}`
39
+
40
+ // Props
41
+ const props = defineProps({
42
+ // 是否为暗色主题
43
+ modelValue: {
44
+ type: Boolean,
45
+ default: false
46
+ }
47
+ })
48
+
49
+ // Emits
50
+ const emit = defineEmits(['update:modelValue', 'change'])
51
+
52
+ // 内部状态
53
+ const toggleRef = ref(null)
54
+ const isDark = ref(props.modelValue)
55
+
56
+ // 监听 prop 变化,同步到内部状态
57
+ watch(() => props.modelValue, (newVal) => {
58
+ isDark.value = newVal
59
+ })
60
+
61
+ // 处理切换
62
+ const handleChange = (event) => {
63
+ const checked = event.target.checked
64
+ isDark.value = checked
65
+ emit('update:modelValue', checked)
66
+ emit('change', checked)
67
+ }
68
+
69
+ // 暴露方法给父组件
70
+ defineExpose({
71
+ toggle: () => {
72
+ if (toggleRef.value) {
73
+ toggleRef.value.click()
74
+ }
75
+ },
76
+ setDark: (value) => {
77
+ isDark.value = value
78
+ emit('update:modelValue', value)
79
+ emit('change', value)
80
+ }
81
+ })
33
82
  </script>
34
83
 
35
84
  <style scoped>
@@ -40,23 +89,13 @@ defineOptions({
40
89
  -webkit-tap-highlight-color: transparent;
41
90
  }
42
91
 
43
- .theme__fill,
44
92
  .theme__icon {
45
93
  transition: 0.3s;
46
94
  }
47
95
 
48
- .theme__fill {
49
- background-color: var(--bg);
50
- display: block;
51
- mix-blend-mode: difference;
52
- position: fixed;
53
- inset: 0;
54
- height: 100%;
55
- transform: translateX(-100%);
56
- }
57
-
58
96
  .theme__icon,
59
97
  .theme__toggle {
98
+ cursor: pointer;
60
99
  z-index: 1;
61
100
  }
62
101
 
@@ -67,27 +106,28 @@ defineOptions({
67
106
 
68
107
  .theme__icon {
69
108
  display: block;
70
- top: 0.5em;
71
- left: 0.5em;
109
+ top: 50%;
110
+ left: 0.7em;
111
+ transform: translateY(-50%);
72
112
  width: 1.5em;
73
113
  height: 1.5em;
74
114
  }
75
115
 
76
116
  .theme__icon-part {
77
117
  border-radius: 50%;
78
- box-shadow: 0.4em -0.4em 0 0.5em hsl(0,0%,100%) inset;
118
+ box-shadow: 0.4em -0.4em 0 0.5em hsl(0, 0%, 100%) inset;
79
119
  top: calc(50% - 0.5em);
80
120
  left: calc(50% - 0.5em);
81
121
  width: 1em;
82
122
  height: 1em;
83
123
  transition: box-shadow var(--transDur) ease-in-out,
84
- opacity var(--transDur) ease-in-out,
85
- transform var(--transDur) ease-in-out;
124
+ opacity var(--transDur) ease-in-out,
125
+ transform var(--transDur) ease-in-out;
86
126
  transform: scale(0.5);
87
127
  }
88
128
 
89
- .theme__icon-part ~ .theme__icon-part {
90
- background-color: hsl(0,0%,100%);
129
+ .theme__icon-part~.theme__icon-part {
130
+ background-color: hsl(0, 0%, 100%);
91
131
  border-radius: 0.05em;
92
132
  top: 50%;
93
133
  left: calc(50% - 0.05em);
@@ -137,7 +177,7 @@ defineOptions({
137
177
  }
138
178
 
139
179
  .theme__toggle {
140
- background-color: hsl(48,90%,85%);
180
+ background-color: hsl(48, 90%, 85%);
141
181
  border-radius: 25% / 50%;
142
182
  box-shadow: 0 0 0 0.125em var(--primaryT);
143
183
  padding: 0.25em;
@@ -146,12 +186,12 @@ defineOptions({
146
186
  -webkit-appearance: none;
147
187
  appearance: none;
148
188
  transition: background-color var(--transDur) ease-in-out,
149
- box-shadow 0.15s ease-in-out,
150
- transform var(--transDur) ease-in-out;
189
+ box-shadow 0.15s ease-in-out,
190
+ transform var(--transDur) ease-in-out;
151
191
  }
152
192
 
153
193
  .theme__toggle:before {
154
- background-color: hsl(48,90%,55%);
194
+ background-color: hsl(48, 90%, 55%);
155
195
  border-radius: 50%;
156
196
  content: "";
157
197
  width: 2.5em;
@@ -166,62 +206,61 @@ defineOptions({
166
206
 
167
207
  /* Checked */
168
208
  .theme__toggle:checked {
169
- background-color: hsl(198,90%,15%);
209
+ background-color: hsl(198, 90%, 15%);
170
210
  }
171
211
 
172
- .theme__toggle:checked:before,
173
- .theme__toggle:checked ~ .theme__icon {
212
+ .theme__toggle:checked:before {
174
213
  transform: translateX(3em);
175
214
  }
176
215
 
177
- .theme__toggle:checked:before {
178
- background-color: hsl(198,90%,55%);
216
+ .theme__toggle:checked~.theme__icon {
217
+ transform: translateX(3em) translateY(-50%);
179
218
  }
180
219
 
181
- .theme__toggle:checked ~ .theme__fill {
182
- transform: translateX(0);
220
+ .theme__toggle:checked:before {
221
+ background-color: hsl(198, 90%, 55%);
183
222
  }
184
223
 
185
- .theme__toggle:checked ~ .theme__icon .theme__icon-part:nth-child(1) {
186
- box-shadow: 0.2em -0.2em 0 0.2em hsl(0,0%,100%) inset;
224
+ .theme__toggle:checked~.theme__icon .theme__icon-part:nth-child(1) {
225
+ box-shadow: 0.2em -0.2em 0 0.2em hsl(0, 0%, 100%) inset;
187
226
  transform: scale(1);
188
- top: 0.2em;
189
- left: -0.2em;
227
+ top: calc(50% - 0.5em);
228
+ left: calc(50% - 0.5em);
190
229
  }
191
230
 
192
- .theme__toggle:checked ~ .theme__icon .theme__icon-part ~ .theme__icon-part {
231
+ .theme__toggle:checked~.theme__icon .theme__icon-part~.theme__icon-part {
193
232
  opacity: 0;
194
233
  }
195
234
 
196
- .theme__toggle:checked ~ .theme__icon .theme__icon-part:nth-child(2) {
235
+ .theme__toggle:checked~.theme__icon .theme__icon-part:nth-child(2) {
197
236
  transform: rotate(45deg) translateY(0.8em);
198
237
  }
199
238
 
200
- .theme__toggle:checked ~ .theme__icon .theme__icon-part:nth-child(3) {
239
+ .theme__toggle:checked~.theme__icon .theme__icon-part:nth-child(3) {
201
240
  transform: rotate(90deg) translateY(0.8em);
202
241
  }
203
242
 
204
- .theme__toggle:checked ~ .theme__icon .theme__icon-part:nth-child(4) {
243
+ .theme__toggle:checked~.theme__icon .theme__icon-part:nth-child(4) {
205
244
  transform: rotate(135deg) translateY(0.8em);
206
245
  }
207
246
 
208
- .theme__toggle:checked ~ .theme__icon .theme__icon-part:nth-child(5) {
247
+ .theme__toggle:checked~.theme__icon .theme__icon-part:nth-child(5) {
209
248
  transform: rotate(180deg) translateY(0.8em);
210
249
  }
211
250
 
212
- .theme__toggle:checked ~ .theme__icon .theme__icon-part:nth-child(6) {
251
+ .theme__toggle:checked~.theme__icon .theme__icon-part:nth-child(6) {
213
252
  transform: rotate(225deg) translateY(0.8em);
214
253
  }
215
254
 
216
- .theme__toggle:checked ~ .theme__icon .theme__icon-part:nth-child(7) {
255
+ .theme__toggle:checked~.theme__icon .theme__icon-part:nth-child(7) {
217
256
  transform: rotate(270deg) translateY(0.8em);
218
257
  }
219
258
 
220
- .theme__toggle:checked ~ .theme__icon .theme__icon-part:nth-child(8) {
259
+ .theme__toggle:checked~.theme__icon .theme__icon-part:nth-child(8) {
221
260
  transform: rotate(315deg) translateY(0.8em);
222
261
  }
223
262
 
224
- .theme__toggle:checked ~ .theme__icon .theme__icon-part:nth-child(9) {
263
+ .theme__toggle:checked~.theme__icon .theme__icon-part:nth-child(9) {
225
264
  transform: rotate(360deg) translateY(0.8em);
226
265
  }
227
266
 
package/src/index.js CHANGED
@@ -24,6 +24,9 @@ import Button from './components/Button.vue'
24
24
  import Card from './components/Card.vue'
25
25
  import Modal from './components/Modal.vue'
26
26
  import Message from './components/Message.vue'
27
+ import Carousel from './components/Carousel.vue'
28
+ import Loading from './components/Loading.vue'
29
+ import Table from './components/Table.vue'
27
30
  import { message } from './components/message.js'
28
31
 
29
32
  // 导入自定义组件(由 Demo 上传生成)
@@ -38,6 +41,9 @@ const components = {
38
41
  Card,
39
42
  Modal,
40
43
  Message,
44
+ Carousel,
45
+ Loading,
46
+ Table,
41
47
  ...customComponents
42
48
  }
43
49
 
@@ -47,6 +53,11 @@ const install = (app, options = {}) => {
47
53
  Object.entries(components).forEach(([name, component]) => {
48
54
  app.component(options.prefix ? `${options.prefix}${name}` : name, component)
49
55
  })
56
+
57
+ // 挂载 message 到全局属性
58
+ app.config.globalProperties.$message = message
59
+ // 同时提供 provide 方式
60
+ app.provide('message', message)
50
61
  }
51
62
 
52
63
  // 导出代码片段相关
@@ -56,7 +67,7 @@ export const registerSnippets = snippetsModule.registerSnippets
56
67
  export const getSnippet = snippetsModule.getSnippet
57
68
 
58
69
  // 导出内置组件(按需引入)
59
- export { Button, Card, Modal, Message, message }
70
+ export { Button, Card, Modal, Message, Carousel, Loading, Table, message }
60
71
 
61
72
  // 重新导出自定义组件
62
73
  export * from './components/custom/index.js'
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Backtop 回到顶部组件示例代码
3
+ */
4
+ export default {
5
+ name: 'Backtop',
6
+ type: 'vue',
7
+ label: 'Backtop 回到顶部',
8
+ code: `<template>
9
+ <!-- 基础用法 -->
10
+ <Backtop />
11
+
12
+ <!-- 指定滚动容器 -->
13
+ <Backtop target=".my-container" :visibility-height="100" />
14
+
15
+ <!-- 自定义内容 -->
16
+ <Backtop>
17
+ <span style="font-size: 12px;">UP</span>
18
+ </Backtop>
19
+ </template>
20
+
21
+ <script setup>
22
+ import { Backtop } from 'little-dizzy'
23
+ </script>`
24
+ }
25
+
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Carousel 轮播图组件示例代码
3
+ */
4
+ export default {
5
+ name: 'Carousel',
6
+ type: 'vue',
7
+ label: 'Carousel 轮播图',
8
+ code: `<template>
9
+ <Carousel :items="items" height="300px" />
10
+ </template>
11
+
12
+ <script setup>
13
+ import { Carousel } from 'little-dizzy'
14
+
15
+ const items = [
16
+ { image: 'https://picsum.photos/800/300?random=1', title: '图片 1' },
17
+ { image: 'https://picsum.photos/800/300?random=2', title: '图片 2' },
18
+ { image: 'https://picsum.photos/800/300?random=3', title: '图片 3' }
19
+ ]
20
+ </script>`
21
+ }
22
+
@@ -8,17 +8,25 @@ import buttonSnippet from './button.js'
8
8
  import cardSnippet from './card.js'
9
9
  import modalSnippet from './modal.js'
10
10
  import messageSnippet from './message.js'
11
+ import carouselSnippet from './carousel.js'
12
+ import loadingSnippet from './loading.js'
13
+ import tableSnippet from './table.js'
14
+ import backtopSnippet from './backtop.js'
11
15
 
12
16
  // 所有预设代码片段
13
17
  export const presetSnippets = [
14
18
  buttonSnippet,
15
19
  cardSnippet,
16
20
  modalSnippet,
17
- messageSnippet
21
+ messageSnippet,
22
+ carouselSnippet,
23
+ loadingSnippet,
24
+ tableSnippet,
25
+ backtopSnippet
18
26
  ]
19
27
 
20
28
  // 单独导出
21
- export { buttonSnippet, cardSnippet, modalSnippet, messageSnippet }
29
+ export { buttonSnippet, cardSnippet, modalSnippet, messageSnippet, carouselSnippet, loadingSnippet, tableSnippet, backtopSnippet }
22
30
 
23
31
  export default presetSnippets
24
32
 
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Loading 加载组件示例代码
3
+ */
4
+ export default {
5
+ name: 'Loading',
6
+ type: 'vue',
7
+ label: 'Loading 加载',
8
+ code: `<template>
9
+ <Loading type="spinner" />
10
+ <Loading type="dots" />
11
+ <Loading type="ring" />
12
+ <Loading type="pulse" />
13
+ <Loading type="bars" />
14
+ </template>
15
+
16
+ <script setup>
17
+ import { Loading } from 'little-dizzy'
18
+ </script>`
19
+ }
20
+
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Table 表格组件示例代码
3
+ */
4
+ export default {
5
+ name: 'Table',
6
+ type: 'vue',
7
+ label: 'Table 表格',
8
+ code: `<template>
9
+ <Table :columns="columns" :data="data" bordered striped />
10
+ </template>
11
+
12
+ <script setup>
13
+ import { Table } from 'little-dizzy'
14
+
15
+ const columns = [
16
+ { key: 'name', title: '姓名', width: '120px' },
17
+ { key: 'age', title: '年龄', width: '80px' },
18
+ { key: 'address', title: '地址' }
19
+ ]
20
+
21
+ const data = [
22
+ { name: '张三', age: 28, address: '北京市朝阳区' },
23
+ { name: '李四', age: 32, address: '上海市浦东新区' },
24
+ { name: '王五', age: 25, address: '广州市天河区' }
25
+ ]
26
+ </script>`
27
+ }
28
+