officialblock 1.0.0 → 1.0.2

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.
Files changed (42) hide show
  1. package/README.md +140 -5
  2. package/dist/official-block.cjs.js +186 -1
  3. package/dist/official-block.es.js +22627 -70
  4. package/dist/official-block.umd.js +186 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +12 -2
  7. package/src/App.vue +32 -82
  8. package/src/components/ArticleList/article.vue +73 -0
  9. package/src/components/ArticleList/contact.vue +95 -0
  10. package/src/components/ArticleList/index.vue +220 -48
  11. package/src/components/ArticleList/setting.vue +407 -0
  12. package/src/components/Button/index.vue +183 -0
  13. package/src/components/HeroSlide/index.ts +1 -0
  14. package/src/components/HeroSlide/index.vue +21 -3
  15. package/src/components/HeroSlide/type.ts +19 -0
  16. package/src/components/Media/index.vue +327 -0
  17. package/src/components/Operate/index.vue +74 -0
  18. package/src/components/RichTextEditor/RichTextEditor.vue +277 -0
  19. package/src/components/RichTextEditor/index.ts +7 -0
  20. package/src/components/ThemePreview/ThemePreview.vue +462 -0
  21. package/src/components/ThemePreview/index.ts +4 -0
  22. package/src/components/index.ts +14 -0
  23. package/src/composables/useTheme.ts +205 -0
  24. package/src/index.ts +26 -8
  25. package/src/main.ts +16 -1
  26. package/src/router/index.ts +84 -0
  27. package/src/style.css +0 -1
  28. package/src/styles/editor.scss +649 -0
  29. package/src/styles/test.scss +20 -0
  30. package/src/styles/variables.scss +639 -0
  31. package/src/types.ts +8 -0
  32. package/src/utils/common.ts +13 -0
  33. package/src/utils/theme.ts +335 -0
  34. package/src/views/Layout.vue +247 -0
  35. package/src/views/NotFound.vue +114 -0
  36. package/src/views/components/ArticleListDemo.vue +167 -0
  37. package/src/views/components/HeroSlideDemo.vue +353 -0
  38. package/src/views/components/RichTextEditorDemo.vue +53 -0
  39. package/src/views/components/ThemeDemo.vue +477 -0
  40. package/src/views/guide/Installation.vue +234 -0
  41. package/src/views/guide/Introduction.vue +174 -0
  42. package/src/views/guide/QuickStart.vue +265 -0
@@ -0,0 +1,462 @@
1
+ <template>
2
+ <div class="theme-preview">
3
+ <div class="preview-header">
4
+ <h3>主题预览</h3>
5
+ <p>实时预览当前主题效果</p>
6
+ </div>
7
+
8
+ <div class="preview-content">
9
+ <!-- 颜色预览 -->
10
+ <div class="color-preview">
11
+ <h4>颜色系统</h4>
12
+ <div class="color-swatches">
13
+ <div
14
+ class="color-swatch primary"
15
+ :style="{ backgroundColor: currentTheme.primaryColor }"
16
+ >
17
+ <span :style="{ color: getTextColor(currentTheme.primaryColor) }">
18
+ Primary
19
+ </span>
20
+ </div>
21
+ <div
22
+ class="color-swatch secondary"
23
+ :style="{ backgroundColor: currentTheme.secondaryColor }"
24
+ >
25
+ <span :style="{ color: getTextColor(currentTheme.secondaryColor) }">
26
+ Secondary
27
+ </span>
28
+ </div>
29
+ <div class="color-swatch success">
30
+ <span>Success</span>
31
+ </div>
32
+ <div class="color-swatch warning">
33
+ <span>Warning</span>
34
+ </div>
35
+ <div class="color-swatch error">
36
+ <span>Error</span>
37
+ </div>
38
+ </div>
39
+ </div>
40
+
41
+ <!-- 字体预览 -->
42
+ <div class="typography-preview">
43
+ <h4>字体系统</h4>
44
+ <div class="font-samples">
45
+ <div
46
+ class="font-sample"
47
+ :style="{
48
+ fontSize: currentTheme.fontSize,
49
+ fontFamily: currentTheme.fontFamily
50
+ }"
51
+ >
52
+ <strong>默认字体 ({{ currentTheme.fontSize }})</strong>
53
+ <p>这是使用当前主题字体设置的示例文本。The quick brown fox jumps over the lazy dog.</p>
54
+ </div>
55
+ </div>
56
+ </div>
57
+
58
+ <!-- 组件预览 -->
59
+ <div class="component-preview">
60
+ <h4>组件预览</h4>
61
+ <div class="component-samples">
62
+ <!-- 按钮 -->
63
+ <div class="sample-group">
64
+ <label>按钮</label>
65
+ <div class="button-group">
66
+ <button
67
+ class="btn btn-primary"
68
+ :style="{
69
+ backgroundColor: currentTheme.primaryColor,
70
+ borderRadius: currentTheme.borderRadius,
71
+ fontSize: currentTheme.fontSize
72
+ }"
73
+ >
74
+ 主要按钮
75
+ </button>
76
+ <button
77
+ class="btn btn-secondary"
78
+ :style="{
79
+ backgroundColor: currentTheme.secondaryColor,
80
+ borderRadius: currentTheme.borderRadius,
81
+ fontSize: currentTheme.fontSize
82
+ }"
83
+ >
84
+ 次要按钮
85
+ </button>
86
+ <button
87
+ class="btn btn-outline"
88
+ :style="{
89
+ borderColor: currentTheme.primaryColor,
90
+ color: currentTheme.primaryColor,
91
+ borderRadius: currentTheme.borderRadius,
92
+ fontSize: currentTheme.fontSize
93
+ }"
94
+ >
95
+ 轮廓按钮
96
+ </button>
97
+ </div>
98
+ </div>
99
+
100
+ <!-- 卡片 -->
101
+ <div class="sample-group">
102
+ <label>卡片</label>
103
+ <div
104
+ class="card-sample"
105
+ :style="{
106
+ borderRadius: currentTheme.borderRadius,
107
+ padding: currentTheme.spacing
108
+ }"
109
+ >
110
+ <h5 :style="{ fontSize: `calc(${currentTheme.fontSize} * 1.2)` }">
111
+ 卡片标题
112
+ </h5>
113
+ <p :style="{ fontSize: currentTheme.fontSize }">
114
+ 这是一个卡片组件的预览示例,展示了当前主题的样式效果。
115
+ </p>
116
+ </div>
117
+ </div>
118
+
119
+ <!-- 输入框 -->
120
+ <div class="sample-group">
121
+ <label>输入框</label>
122
+ <input
123
+ type="text"
124
+ class="input-sample"
125
+ placeholder="输入框示例"
126
+ :style="{
127
+ borderRadius: currentTheme.borderRadius,
128
+ fontSize: currentTheme.fontSize,
129
+ padding: `calc(${currentTheme.spacing} * 0.5) ${currentTheme.spacing}`
130
+ }"
131
+ >
132
+ </div>
133
+
134
+ <!-- 标签 -->
135
+ <div class="sample-group">
136
+ <label>标签</label>
137
+ <div class="tag-group">
138
+ <span
139
+ class="tag tag-primary"
140
+ :style="{
141
+ backgroundColor: `${currentTheme.primaryColor}20`,
142
+ color: currentTheme.primaryColor,
143
+ borderRadius: `calc(${currentTheme.borderRadius} * 0.5)`,
144
+ fontSize: `calc(${currentTheme.fontSize} * 0.875)`,
145
+ padding: `calc(${currentTheme.spacing} * 0.25) calc(${currentTheme.spacing} * 0.5)`
146
+ }"
147
+ >
148
+ 主要标签
149
+ </span>
150
+ <span
151
+ class="tag tag-secondary"
152
+ :style="{
153
+ backgroundColor: `${currentTheme.secondaryColor}20`,
154
+ color: currentTheme.secondaryColor,
155
+ borderRadius: `calc(${currentTheme.borderRadius} * 0.5)`,
156
+ fontSize: `calc(${currentTheme.fontSize} * 0.875)`,
157
+ padding: `calc(${currentTheme.spacing} * 0.25) calc(${currentTheme.spacing} * 0.5)`
158
+ }"
159
+ >
160
+ 次要标签
161
+ </span>
162
+ </div>
163
+ </div>
164
+ </div>
165
+ </div>
166
+
167
+ <!-- 布局预览 -->
168
+ <div class="layout-preview">
169
+ <h4>布局预览</h4>
170
+ <div
171
+ class="layout-sample"
172
+ :style="{ gap: currentTheme.spacing }"
173
+ >
174
+ <div
175
+ class="layout-item"
176
+ :style="{
177
+ borderRadius: currentTheme.borderRadius,
178
+ padding: currentTheme.spacing
179
+ }"
180
+ >
181
+ <div class="item-header">
182
+ <div
183
+ class="item-avatar"
184
+ :style="{
185
+ backgroundColor: currentTheme.primaryColor,
186
+ borderRadius: currentTheme.borderRadius
187
+ }"
188
+ ></div>
189
+ <div class="item-info">
190
+ <h6 :style="{ fontSize: currentTheme.fontSize }">用户名称</h6>
191
+ <p :style="{ fontSize: `calc(${currentTheme.fontSize} * 0.875)` }">
192
+ 用户描述信息
193
+ </p>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ <div
198
+ class="layout-item"
199
+ :style="{
200
+ borderRadius: currentTheme.borderRadius,
201
+ padding: currentTheme.spacing
202
+ }"
203
+ >
204
+ <div class="item-content">
205
+ <h6 :style="{ fontSize: currentTheme.fontSize }">内容标题</h6>
206
+ <p :style="{ fontSize: `calc(${currentTheme.fontSize} * 0.875)` }">
207
+ 这是一段示例内容,用于展示当前主题的布局效果。
208
+ </p>
209
+ </div>
210
+ </div>
211
+ </div>
212
+ </div>
213
+ </div>
214
+ </div>
215
+ </template>
216
+
217
+ <script setup lang="ts">
218
+ import { useTheme } from '@/composables/useTheme'
219
+ import { ThemeUtils } from '@/utils/theme'
220
+
221
+ const { currentTheme } = useTheme()
222
+
223
+ // 获取文本颜色
224
+ const getTextColor = (backgroundColor: string) => {
225
+ return ThemeUtils.getBestTextColor(backgroundColor)
226
+ }
227
+ </script>
228
+
229
+ <style scoped>
230
+ .theme-preview {
231
+ border: 1px solid var(--theme-gray-200);
232
+ border-radius: var(--radius-lg);
233
+ padding: var(--spacing-lg);
234
+ background: var(--theme-gray-50);
235
+ }
236
+
237
+ .preview-header {
238
+ margin-bottom: var(--spacing-lg);
239
+ }
240
+
241
+ .preview-header h3 {
242
+ margin: 0 0 var(--spacing-sm) 0;
243
+ font-size: var(--font-size-lg);
244
+ font-weight: 600;
245
+ color: var(--theme-gray-900);
246
+ }
247
+
248
+ .preview-header p {
249
+ margin: 0;
250
+ font-size: var(--font-size-sm);
251
+ color: var(--theme-gray-600);
252
+ }
253
+
254
+ .preview-content {
255
+ display: grid;
256
+ gap: var(--spacing-xl);
257
+ }
258
+
259
+ .preview-content h4 {
260
+ margin: 0 0 var(--spacing-md) 0;
261
+ font-size: var(--font-size-base);
262
+ font-weight: 600;
263
+ color: var(--theme-gray-800);
264
+ }
265
+
266
+ /* 颜色预览 */
267
+ .color-swatches {
268
+ display: grid;
269
+ grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
270
+ gap: var(--spacing-sm);
271
+ }
272
+
273
+ .color-swatch {
274
+ height: 60px;
275
+ border-radius: var(--radius-md);
276
+ display: flex;
277
+ align-items: center;
278
+ justify-content: center;
279
+ font-weight: 500;
280
+ font-size: var(--font-size-sm);
281
+ transition: transform var(--transition-fast);
282
+ }
283
+
284
+ .color-swatch:hover {
285
+ transform: translateY(-2px);
286
+ }
287
+
288
+ .color-swatch.success {
289
+ background-color: var(--theme-success);
290
+ color: white;
291
+ }
292
+
293
+ .color-swatch.warning {
294
+ background-color: var(--theme-warning);
295
+ color: white;
296
+ }
297
+
298
+ .color-swatch.error {
299
+ background-color: var(--theme-error);
300
+ color: white;
301
+ }
302
+
303
+ /* 字体预览 */
304
+ .font-sample p {
305
+ margin: var(--spacing-sm) 0 0 0;
306
+ line-height: var(--line-height-relaxed);
307
+ color: var(--theme-gray-700);
308
+ }
309
+
310
+ /* 组件预览 */
311
+ .component-samples {
312
+ display: grid;
313
+ gap: var(--spacing-lg);
314
+ }
315
+
316
+ .sample-group label {
317
+ display: block;
318
+ margin-bottom: var(--spacing-sm);
319
+ font-weight: 500;
320
+ font-size: var(--font-size-sm);
321
+ color: var(--theme-gray-700);
322
+ }
323
+
324
+ .button-group {
325
+ display: flex;
326
+ gap: var(--spacing-sm);
327
+ flex-wrap: wrap;
328
+ }
329
+
330
+ .btn {
331
+ padding: var(--spacing-sm) var(--spacing-md);
332
+ border: 1px solid transparent;
333
+ cursor: pointer;
334
+ font-weight: 500;
335
+ transition: all var(--transition-fast);
336
+ }
337
+
338
+ .btn:hover {
339
+ transform: translateY(-1px);
340
+ box-shadow: var(--shadow-md);
341
+ }
342
+
343
+ .btn-primary {
344
+ color: white;
345
+ border-color: transparent;
346
+ }
347
+
348
+ .btn-secondary {
349
+ color: white;
350
+ border-color: transparent;
351
+ }
352
+
353
+ .btn-outline {
354
+ background: transparent;
355
+ border-width: 1px;
356
+ }
357
+
358
+ .card-sample {
359
+ background: white;
360
+ border: 1px solid var(--theme-gray-200);
361
+ box-shadow: var(--shadow-sm);
362
+ }
363
+
364
+ .card-sample h5 {
365
+ margin: 0 0 var(--spacing-sm) 0;
366
+ font-weight: 600;
367
+ color: var(--theme-gray-900);
368
+ }
369
+
370
+ .card-sample p {
371
+ margin: 0;
372
+ color: var(--theme-gray-600);
373
+ line-height: var(--line-height-normal);
374
+ }
375
+
376
+ .input-sample {
377
+ width: 100%;
378
+ max-width: 300px;
379
+ border: 1px solid var(--theme-gray-300);
380
+ background: white;
381
+ color: var(--theme-gray-900);
382
+ outline: none;
383
+ transition: border-color var(--transition-fast);
384
+ }
385
+
386
+ .input-sample:focus {
387
+ border-color: var(--theme-primary);
388
+ }
389
+
390
+ .tag-group {
391
+ display: flex;
392
+ gap: var(--spacing-sm);
393
+ flex-wrap: wrap;
394
+ }
395
+
396
+ .tag {
397
+ display: inline-block;
398
+ font-weight: 500;
399
+ }
400
+
401
+ /* 布局预览 */
402
+ .layout-sample {
403
+ display: grid;
404
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
405
+ }
406
+
407
+ .layout-item {
408
+ background: white;
409
+ border: 1px solid var(--theme-gray-200);
410
+ box-shadow: var(--shadow-sm);
411
+ }
412
+
413
+ .item-header {
414
+ display: flex;
415
+ align-items: center;
416
+ gap: var(--spacing-md);
417
+ }
418
+
419
+ .item-avatar {
420
+ width: 40px;
421
+ height: 40px;
422
+ flex-shrink: 0;
423
+ }
424
+
425
+ .item-info h6 {
426
+ margin: 0 0 var(--spacing-xs) 0;
427
+ font-weight: 600;
428
+ color: var(--theme-gray-900);
429
+ }
430
+
431
+ .item-info p {
432
+ margin: 0;
433
+ color: var(--theme-gray-600);
434
+ }
435
+
436
+ .item-content h6 {
437
+ margin: 0 0 var(--spacing-sm) 0;
438
+ font-weight: 600;
439
+ color: var(--theme-gray-900);
440
+ }
441
+
442
+ .item-content p {
443
+ margin: 0;
444
+ color: var(--theme-gray-600);
445
+ line-height: var(--line-height-normal);
446
+ }
447
+
448
+ @media (max-width: 768px) {
449
+ .color-swatches {
450
+ grid-template-columns: repeat(2, 1fr);
451
+ }
452
+
453
+ .button-group {
454
+ flex-direction: column;
455
+ align-items: flex-start;
456
+ }
457
+
458
+ .layout-sample {
459
+ grid-template-columns: 1fr;
460
+ }
461
+ }
462
+ </style>
@@ -0,0 +1,4 @@
1
+ import ThemePreview from './ThemePreview.vue'
2
+
3
+ export default ThemePreview
4
+ export { ThemePreview }
@@ -0,0 +1,14 @@
1
+ // 导出所有组件
2
+ export { default as ArticleList } from './ArticleList/index.vue'
3
+ export { default as HeroSlide } from './HeroSlide/index.vue'
4
+ export { default as RichTextEditor } from './RichTextEditor'
5
+ export { default as ThemePreview } from './ThemePreview'
6
+
7
+ // 导出组件插件
8
+ export { default as ArticleListPlugin } from './ArticleList/index'
9
+ export { default as HeroSlidePlugin } from './HeroSlide/index'
10
+
11
+ // 导出类型定义
12
+ export type { ComponentProps, ComponentEmits, ComponentSlots } from './ArticleList/type'
13
+ export type { HeroSlideProps, HeroSlideEmits, SlideItem } from './HeroSlide/type'
14
+ export type { IDomEditor, IEditorConfig, IToolbarConfig } from './RichTextEditor'
@@ -0,0 +1,205 @@
1
+ import { ref, computed } from 'vue'
2
+
3
+ // 主题配置接口
4
+ export interface ThemeConfig {
5
+ primaryColor: string
6
+ secondaryColor: string
7
+ fontSize: string
8
+ fontFamily: string
9
+ borderRadius: string
10
+ spacing: string
11
+ }
12
+
13
+ // 预设主题
14
+ export const themePresets = {
15
+ default: {
16
+ primaryColor: '#3b82f6',
17
+ secondaryColor: '#a855f7',
18
+ fontSize: '14px',
19
+ fontFamily: 'Inter, sans-serif',
20
+ borderRadius: '6px',
21
+ spacing: '16px'
22
+ },
23
+ dark: {
24
+ primaryColor: '#60a5fa',
25
+ secondaryColor: '#c084fc',
26
+ fontSize: '14px',
27
+ fontFamily: 'Inter, sans-serif',
28
+ borderRadius: '6px',
29
+ spacing: '16px'
30
+ },
31
+ compact: {
32
+ primaryColor: '#3b82f6',
33
+ secondaryColor: '#a855f7',
34
+ fontSize: '12px',
35
+ fontFamily: 'Inter, sans-serif',
36
+ borderRadius: '4px',
37
+ spacing: '12px'
38
+ },
39
+ large: {
40
+ primaryColor: '#3b82f6',
41
+ secondaryColor: '#a855f7',
42
+ fontSize: '16px',
43
+ fontFamily: 'Inter, sans-serif',
44
+ borderRadius: '8px',
45
+ spacing: '20px'
46
+ }
47
+ }
48
+
49
+ // 当前主题状态
50
+ const currentTheme = ref<ThemeConfig>(themePresets.default)
51
+ const isDarkMode = ref(false)
52
+
53
+ // 主题组合式函数
54
+ export function useTheme() {
55
+ // 设置主题
56
+ const setTheme = (theme: ThemeConfig | keyof typeof themePresets) => {
57
+ if (typeof theme === 'string') {
58
+ currentTheme.value = { ...themePresets[theme] }
59
+ } else {
60
+ currentTheme.value = { ...theme }
61
+ }
62
+ applyThemeToDOM()
63
+ }
64
+
65
+ // 更新主题属性
66
+ const updateTheme = (updates: Partial<ThemeConfig>) => {
67
+ currentTheme.value = { ...currentTheme.value, ...updates }
68
+ applyThemeToDOM()
69
+ }
70
+
71
+ // 切换暗色模式
72
+ const toggleDarkMode = () => {
73
+ isDarkMode.value = !isDarkMode.value
74
+ document.documentElement.classList.toggle('dark', isDarkMode.value)
75
+ }
76
+
77
+ // 应用主题到DOM
78
+ const applyThemeToDOM = () => {
79
+ const root = document.documentElement
80
+ const theme = currentTheme.value
81
+
82
+ // 设置CSS变量
83
+ root.style.setProperty('--theme-primary', theme.primaryColor)
84
+ root.style.setProperty('--theme-secondary', theme.secondaryColor)
85
+ root.style.setProperty('--font-size-default', theme.fontSize)
86
+ root.style.setProperty('--font-family-sans', theme.fontFamily)
87
+ root.style.setProperty('--radius-md', theme.borderRadius)
88
+ root.style.setProperty('--spacing-md', theme.spacing)
89
+ }
90
+
91
+ // 获取主题颜色
92
+ const getThemeColor = (color: 'primary' | 'secondary') => {
93
+ return computed(() => {
94
+ return color === 'primary' ? currentTheme.value.primaryColor : currentTheme.value.secondaryColor
95
+ })
96
+ }
97
+
98
+ // 获取字体大小
99
+ const getFontSize = () => {
100
+ return computed(() => currentTheme.value.fontSize)
101
+ }
102
+
103
+ // 获取字体族
104
+ const getFontFamily = () => {
105
+ return computed(() => currentTheme.value.fontFamily)
106
+ }
107
+
108
+ // 获取圆角大小
109
+ const getBorderRadius = () => {
110
+ return computed(() => currentTheme.value.borderRadius)
111
+ }
112
+
113
+ // 获取间距大小
114
+ const getSpacing = () => {
115
+ return computed(() => currentTheme.value.spacing)
116
+ }
117
+
118
+ // 重置主题
119
+ const resetTheme = () => {
120
+ setTheme('default')
121
+ isDarkMode.value = false
122
+ document.documentElement.classList.remove('dark')
123
+ }
124
+
125
+ // 导出主题配置
126
+ const exportTheme = () => {
127
+ return JSON.stringify(currentTheme.value, null, 2)
128
+ }
129
+
130
+ // 导入主题配置
131
+ const importTheme = (themeJson: string) => {
132
+ try {
133
+ const theme = JSON.parse(themeJson) as ThemeConfig
134
+ setTheme(theme)
135
+ return true
136
+ } catch (error) {
137
+ console.error('Invalid theme configuration:', error)
138
+ return false
139
+ }
140
+ }
141
+
142
+ // 初始化主题
143
+ const initTheme = () => {
144
+ // 从localStorage恢复主题设置
145
+ const savedTheme = localStorage.getItem('officialblock-theme')
146
+ const savedDarkMode = localStorage.getItem('officialblock-dark-mode')
147
+
148
+ if (savedTheme) {
149
+ try {
150
+ const theme = JSON.parse(savedTheme) as ThemeConfig
151
+ setTheme(theme)
152
+ } catch (error) {
153
+ console.error('Failed to restore theme:', error)
154
+ }
155
+ }
156
+
157
+ if (savedDarkMode) {
158
+ isDarkMode.value = savedDarkMode === 'true'
159
+ document.documentElement.classList.toggle('dark', isDarkMode.value)
160
+ }
161
+
162
+ // 监听系统主题变化
163
+ const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
164
+ const handleSystemThemeChange = (e: MediaQueryListEvent) => {
165
+ if (!localStorage.getItem('officialblock-dark-mode')) {
166
+ isDarkMode.value = e.matches
167
+ document.documentElement.classList.toggle('dark', isDarkMode.value)
168
+ }
169
+ }
170
+ mediaQuery.addEventListener('change', handleSystemThemeChange)
171
+
172
+ // 初始应用主题
173
+ applyThemeToDOM()
174
+ }
175
+
176
+ // 保存主题设置
177
+ const saveTheme = () => {
178
+ localStorage.setItem('officialblock-theme', JSON.stringify(currentTheme.value))
179
+ localStorage.setItem('officialblock-dark-mode', isDarkMode.value.toString())
180
+ }
181
+
182
+ return {
183
+ // 状态
184
+ currentTheme: computed(() => currentTheme.value),
185
+ isDarkMode: computed(() => isDarkMode.value),
186
+ themePresets,
187
+
188
+ // 方法
189
+ setTheme,
190
+ updateTheme,
191
+ toggleDarkMode,
192
+ resetTheme,
193
+ exportTheme,
194
+ importTheme,
195
+ initTheme,
196
+ saveTheme,
197
+
198
+ // 计算属性
199
+ getThemeColor,
200
+ getFontSize,
201
+ getFontFamily,
202
+ getBorderRadius,
203
+ getSpacing
204
+ }
205
+ }