officialblock 1.0.1 → 1.0.3

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 (40) hide show
  1. package/README.md +25 -1
  2. package/dist/official-block.cjs.js +195 -1
  3. package/dist/official-block.es.js +27230 -72
  4. package/dist/official-block.umd.js +195 -1
  5. package/dist/style.css +1 -1
  6. package/package.json +13 -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 -46
  11. package/src/components/ArticleList/setting.vue +709 -0
  12. package/src/components/Button/index.vue +183 -0
  13. package/src/components/Media/index.vue +327 -0
  14. package/src/components/Operate/index.vue +74 -0
  15. package/src/components/RichTextEditor/RichTextEditor.vue +277 -0
  16. package/src/components/RichTextEditor/index.ts +7 -0
  17. package/src/components/ThemePreview/ThemePreview.vue +462 -0
  18. package/src/components/ThemePreview/index.ts +4 -0
  19. package/src/components/index.ts +3 -0
  20. package/src/composables/useTheme.ts +205 -0
  21. package/src/index.ts +15 -4
  22. package/src/main.ts +16 -1
  23. package/src/router/index.ts +96 -0
  24. package/src/style.css +2 -4
  25. package/src/styles/editor.scss +649 -0
  26. package/src/styles/test.scss +20 -0
  27. package/src/styles/variables.scss +669 -0
  28. package/src/utils/common.ts +13 -0
  29. package/src/utils/theme.ts +335 -0
  30. package/src/views/Layout.vue +250 -0
  31. package/src/views/NotFound.vue +114 -0
  32. package/src/views/components/ArticleListDemo.vue +166 -0
  33. package/src/views/components/DragLimitDemo.vue +573 -0
  34. package/src/views/components/DragSortDemo.vue +610 -0
  35. package/src/views/components/HeroSlideDemo.vue +353 -0
  36. package/src/views/components/RichTextEditorDemo.vue +53 -0
  37. package/src/views/components/ThemeDemo.vue +477 -0
  38. package/src/views/guide/Installation.vue +234 -0
  39. package/src/views/guide/Introduction.vue +174 -0
  40. package/src/views/guide/QuickStart.vue +265 -0
@@ -0,0 +1,277 @@
1
+ <template>
2
+ <div class="rich-text-editor">
3
+ <!-- 工具栏 -->
4
+ <Toolbar
5
+ class="editor-toolbar"
6
+ :editor="editorRef"
7
+ :defaultConfig="toolbarConfig"
8
+ :mode="mode"
9
+ />
10
+
11
+ <!-- 编辑器 -->
12
+ <Editor
13
+ class="editor-content"
14
+ :style="{ height: editorHeight }"
15
+ v-model="valueHtml"
16
+ :defaultConfig="editorConfig"
17
+ :mode="mode"
18
+ @onCreated="handleCreated"
19
+ @onChange="handleChange"
20
+ @onDestroyed="handleDestroyed"
21
+ @onFocus="handleFocus"
22
+ @onBlur="handleBlur"
23
+ />
24
+ </div>
25
+ </template>
26
+
27
+ <script setup lang="ts">
28
+ import '@wangeditor/editor/dist/css/style.css'
29
+ import { onBeforeUnmount, ref, shallowRef, watch, computed } from 'vue'
30
+ import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
31
+ import type { IToolbarConfig, IDomEditor, IEditorConfig } from '@wangeditor/editor'
32
+
33
+ // 组件属性定义
34
+ interface Props {
35
+ modelValue?: string
36
+ placeholder?: string
37
+ height?: string | number
38
+ mode?: 'default' | 'simple'
39
+ disabled?: boolean
40
+ maxLength?: number
41
+ excludeKeys?: string[]
42
+ includeKeys?: string[]
43
+ uploadImgServer?: string
44
+ uploadVideoServer?: string
45
+ }
46
+
47
+ // 事件定义
48
+ interface Emits {
49
+ (e: 'update:modelValue', value: string): void
50
+ (e: 'change', editor: IDomEditor): void
51
+ (e: 'focus', editor: IDomEditor): void
52
+ (e: 'blur', editor: IDomEditor): void
53
+ (e: 'created', editor: IDomEditor): void
54
+ }
55
+
56
+ const props = withDefaults(defineProps<Props>(), {
57
+ modelValue: '',
58
+ placeholder: '请输入内容...',
59
+ height: '400px',
60
+ mode: 'default',
61
+ disabled: false,
62
+ maxLength: 10000,
63
+ excludeKeys: () => [],
64
+ includeKeys: () => [],
65
+ uploadImgServer: '',
66
+ uploadVideoServer: ''
67
+ })
68
+
69
+ const emit = defineEmits<Emits>()
70
+
71
+ // 编辑器实例,必须用 shallowRef
72
+ const editorRef = shallowRef<IDomEditor>()
73
+
74
+ // 内容 HTML
75
+ const valueHtml = ref('')
76
+
77
+ // 计算编辑器高度
78
+ const editorHeight = computed(() => {
79
+ if (typeof props.height === 'number') {
80
+ return `${props.height}px`
81
+ }
82
+ return props.height
83
+ })
84
+
85
+ // 工具栏配置
86
+ const toolbarConfig: Partial<IToolbarConfig> = {
87
+ excludeKeys: props.excludeKeys,
88
+ insertKeys: {
89
+ index: 0,
90
+ keys: props.includeKeys
91
+ }
92
+ }
93
+
94
+ // 编辑器配置
95
+ const editorConfig: Partial<IEditorConfig> = {
96
+ placeholder: props.placeholder,
97
+ readOnly: props.disabled,
98
+ maxLength: props.maxLength,
99
+ MENU_CONF: {
100
+ // 上传图片配置
101
+ uploadImage: {
102
+ server: props.uploadImgServer,
103
+ fieldName: 'file',
104
+ maxFileSize: 5 * 1024 * 1024, // 5M
105
+ allowedFileTypes: ['image/*'],
106
+ meta: {},
107
+ headers: {},
108
+ withCredentials: false,
109
+ timeout: 30 * 1000, // 30s
110
+ onBeforeUpload(file: File) {
111
+ console.log('onBeforeUpload', file)
112
+ return file
113
+ },
114
+ onProgress(progress: number) {
115
+ console.log('onProgress', progress)
116
+ },
117
+ onSuccess(file: File, res: any) {
118
+ console.log('onSuccess', file, res)
119
+ },
120
+ onFailed(file: File, res: any) {
121
+ console.log('onFailed', file, res)
122
+ },
123
+ onError(file: File, err: any) {
124
+ console.log('onError', file, err)
125
+ }
126
+ },
127
+ // 上传视频配置
128
+ uploadVideo: {
129
+ server: props.uploadVideoServer,
130
+ fieldName: 'file',
131
+ maxFileSize: 50 * 1024 * 1024, // 50M
132
+ allowedFileTypes: ['video/*'],
133
+ meta: {},
134
+ headers: {},
135
+ withCredentials: false,
136
+ timeout: 60 * 1000, // 60s
137
+ onBeforeUpload(file: File) {
138
+ console.log('onBeforeUpload video', file)
139
+ return file
140
+ },
141
+ onProgress(progress: number) {
142
+ console.log('onProgress video', progress)
143
+ },
144
+ onSuccess(file: File, res: any) {
145
+ console.log('onSuccess video', file, res)
146
+ },
147
+ onFailed(file: File, res: any) {
148
+ console.log('onFailed video', file, res)
149
+ },
150
+ onError(file: File, err: any) {
151
+ console.log('onError video', file, err)
152
+ }
153
+ }
154
+ }
155
+ }
156
+
157
+ // 组件销毁时,也及时销毁编辑器
158
+ onBeforeUnmount(() => {
159
+ const editor = editorRef.value
160
+ if (editor == null) return
161
+ editor.destroy()
162
+ })
163
+
164
+ // 监听外部传入的内容变化
165
+ watch(
166
+ () => props.modelValue,
167
+ (newVal) => {
168
+ if (newVal !== valueHtml.value) {
169
+ valueHtml.value = newVal || ''
170
+ }
171
+ },
172
+ { immediate: true }
173
+ )
174
+
175
+ // 编辑器回调函数
176
+ const handleCreated = (editor: IDomEditor) => {
177
+ editorRef.value = editor
178
+ emit('created', editor)
179
+ }
180
+
181
+ const handleChange = (editor: IDomEditor) => {
182
+ emit('update:modelValue', valueHtml.value)
183
+ emit('change', editor)
184
+ }
185
+
186
+ const handleDestroyed = () => {
187
+ editorRef.value = undefined
188
+ }
189
+
190
+ const handleFocus = (editor: IDomEditor) => {
191
+ emit('focus', editor)
192
+ }
193
+
194
+ const handleBlur = (editor: IDomEditor) => {
195
+ emit('blur', editor)
196
+ }
197
+
198
+ // 暴露编辑器实例和方法
199
+ defineExpose({
200
+ editor: editorRef,
201
+ getHtml: () => valueHtml.value,
202
+ getText: () => editorRef.value?.getText() || '',
203
+ isEmpty: () => editorRef.value?.isEmpty() || true,
204
+ clear: () => editorRef.value?.clear(),
205
+ focus: () => editorRef.value?.focus(),
206
+ blur: () => editorRef.value?.blur(),
207
+ disable: () => editorRef.value?.disable(),
208
+ enable: () => editorRef.value?.enable()
209
+ })
210
+ </script>
211
+
212
+ <style scoped>
213
+ .rich-text-editor {
214
+ border: 1px solid var(--color-border-2);
215
+ border-radius: 6px;
216
+ overflow: hidden;
217
+ background: #fff;
218
+ height: 300px;
219
+ }
220
+
221
+ .editor-toolbar {
222
+ border-bottom: 1px solid var(--color-border-2);
223
+ background: var(--color-bg-1);
224
+ }
225
+
226
+ .editor-content {
227
+ overflow-y: auto;
228
+ }
229
+
230
+ /* 编辑器内容样式 */
231
+ :deep(.w-e-text-container) {
232
+ background: #fff;
233
+ }
234
+
235
+ :deep(.w-e-text-placeholder) {
236
+ color: var(--color-text-3);
237
+ }
238
+
239
+ /* 工具栏样式调整 */
240
+ :deep(.w-e-toolbar) {
241
+ border-bottom: none;
242
+ background: transparent;
243
+ }
244
+
245
+ :deep(.w-e-bar-item) {
246
+ height: 30px;
247
+ }
248
+
249
+ :deep(.w-e-bar-divider) {
250
+ height: 30px;
251
+ }
252
+
253
+ :deep(.w-e-toolbar .w-e-bar-item button) {
254
+ border-radius: 4px;
255
+ transition: all 0.2s;
256
+ }
257
+
258
+ :deep(.w-e-toolbar .w-e-bar-item button:hover) {
259
+ background: var(--color-fill-2);
260
+ }
261
+
262
+ :deep(.w-e-toolbar .w-e-bar-item button.active) {
263
+ background: rgb(var(--primary-1));
264
+ color: rgb(var(--primary-6));
265
+ }
266
+
267
+ /* 禁用状态样式 */
268
+ .rich-text-editor.disabled {
269
+ background: var(--color-bg-2);
270
+ cursor: not-allowed;
271
+ }
272
+
273
+ .rich-text-editor.disabled :deep(.w-e-text-container) {
274
+ background: var(--color-bg-2);
275
+ cursor: not-allowed;
276
+ }
277
+ </style>
@@ -0,0 +1,7 @@
1
+ import RichTextEditor from './RichTextEditor.vue'
2
+
3
+ export default RichTextEditor
4
+ export { RichTextEditor }
5
+
6
+ // 导出类型定义
7
+ export type { IDomEditor, IEditorConfig, IToolbarConfig } from '@wangeditor/editor'