@opendesign-plus-test/components 0.0.1-rc.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 (52) hide show
  1. package/dist/components.cjs.js +1 -0
  2. package/dist/components.css +1 -0
  3. package/dist/components.es.js +1193 -0
  4. package/dist/components.umd.js +1 -0
  5. package/docs/design.md +27 -0
  6. package/docs/design_banner.md +41 -0
  7. package/docs/design_section.md +27 -0
  8. package/package.json +47 -0
  9. package/scripts/generate-components-index.js +81 -0
  10. package/src/assets/svg-icons/icon-chevron-right.svg +3 -0
  11. package/src/assets/svg-icons/icon-close.svg +3 -0
  12. package/src/assets/svg-icons/icon-delete.svg +3 -0
  13. package/src/assets/svg-icons/icon-header-back.svg +3 -0
  14. package/src/assets/svg-icons/icon-header-delete.svg +3 -0
  15. package/src/assets/svg-icons/icon-header-search.svg +4 -0
  16. package/src/assets/svg-icons/icon-moon.svg +3 -0
  17. package/src/assets/svg-icons/icon-sun.svg +3 -0
  18. package/src/components/OBanner.vue +390 -0
  19. package/src/components/OCookieNotice.vue +417 -0
  20. package/src/components/OCookieNoticeEl.vue +403 -0
  21. package/src/components/OHeaderSearch.vue +601 -0
  22. package/src/components/OPlusConfigProvider.vue +32 -0
  23. package/src/components/OSection.vue +178 -0
  24. package/src/components/OThemeSwitcher.vue +108 -0
  25. package/src/components/common/ClientOnlyWrapper.ts +21 -0
  26. package/src/components/common/ContentWrapper.vue +85 -0
  27. package/src/draft/Banner.vue +265 -0
  28. package/src/draft/ButtonCards.vue +106 -0
  29. package/src/draft/Feature.vue +134 -0
  30. package/src/draft/Footer.vue +512 -0
  31. package/src/draft/HorizontalAnchor.vue +165 -0
  32. package/src/draft/ItemSwiper.vue +133 -0
  33. package/src/draft/Logo.vue +141 -0
  34. package/src/draft/LogoCard.vue +75 -0
  35. package/src/draft/LogoV2.vue +19 -0
  36. package/src/draft/MainCard.vue +38 -0
  37. package/src/draft/MultiCard.vue +95 -0
  38. package/src/draft/MultiIconCard.vue +74 -0
  39. package/src/draft/OInfoCard.vue +176 -0
  40. package/src/draft/Process.vue +81 -0
  41. package/src/draft/Section.vue +167 -0
  42. package/src/draft/SingleTabCard.vue +85 -0
  43. package/src/draft/SliderCard.vue +110 -0
  44. package/src/env.d.ts +1 -0
  45. package/src/i18n/en.ts +20 -0
  46. package/src/i18n/index.ts +42 -0
  47. package/src/i18n/zh.ts +9 -0
  48. package/src/index.ts +34 -0
  49. package/src/shared/provide.ts +6 -0
  50. package/src/vue.d.ts +10 -0
  51. package/tsconfig.json +33 -0
  52. package/vite.config.ts +90 -0
@@ -0,0 +1,601 @@
1
+ <script setup lang="ts">
2
+ import { computed, onMounted, ref, watch } from 'vue';
3
+ import { OIcon, OInput, ODivider } from '@opensig/opendesign';
4
+ import { onClickOutside } from '@vueuse/core';
5
+ import { useScreen } from '@opendesign-plus/composables';
6
+
7
+ import IconClose from '~icons/components/icon-close.svg';
8
+ import IconSearch from '~icons/components/icon-header-search.svg';
9
+ import IconDelete from '~icons/components/icon-header-delete.svg';
10
+ import IconDeleteAll from '~icons/components/icon-delete.svg';
11
+ import IconBack from '~icons/components/icon-header-back.svg';
12
+
13
+ import { useI18n } from '@/i18n';
14
+
15
+ export interface OHeaderSearchPropsT {
16
+ modelValue?: string;
17
+ placeholder?: string; // 搜索框默认提示
18
+ expandedPlaceholder?: string; // 搜索框展开后提示
19
+ expandDirection?: 'left' | 'right'; // 搜索框展开方向,默认为 left
20
+ clearable?: boolean; // 是否显示清除按钮,默认显示
21
+ historyItems?: string[]; // 搜索历史记录
22
+ maxHistoryCount?: number; // 最多保存的搜索历史记录数,默认 6 条
23
+ storeHistory?: boolean; // 是否使用 localStorage 存储搜索历史记录,存储之后初始化时会自动加载搜索历史记录,默认为 false,
24
+ historyTitle?: string; // 历史记录标题
25
+ storageKey?: string; // localStorage 存储搜索历史记录的 key,默认为 search-history
26
+ hotItems?: string[]; // 热门搜索
27
+ hotTitle?: string; // 推荐搜索标题
28
+ recommendItems?: string[]; // 推荐搜索
29
+ searchUrl?: string; // 搜索页面 url,不为空点击热门搜索、历史记录、推荐搜索和回车搜索时自动打开页面
30
+ searchUrlOpenBlank?: boolean; // 是否在新窗口打开搜索页面,默认为 true
31
+ searchTextMobile?: string; // 手机端搜索按钮文字,默认为搜索
32
+ }
33
+
34
+ export interface OHeaderSearchEmitsT {
35
+ (e: 'update:modelValue', value: string): void;
36
+ (e: 'update:historyItems', value: string[]): void;
37
+ (e: 'clear'): void;
38
+ (e: 'search', value: string): void;
39
+ (e: 'delete-history', value: string[]): void;
40
+ (e: 'delete-history-item', value: string): void;
41
+ }
42
+ const { lePadV } = useScreen();
43
+ const { t } = useI18n();
44
+
45
+ const props = withDefaults(defineProps<OHeaderSearchPropsT>(), {
46
+ modelValue: '',
47
+ expandDirection: 'left',
48
+ clearable: true,
49
+ historyItems: () => [],
50
+ maxHistoryCount: 6,
51
+ storeHistory: false,
52
+ storageKey: 'search-history',
53
+ hotItems: () => [],
54
+ recommendItems: () => [],
55
+ searchUrlOpenBlank: true,
56
+ });
57
+
58
+ const emit = defineEmits<OHeaderSearchEmitsT>();
59
+
60
+ const searchInput = ref(props.modelValue);
61
+ const searchHistoryItems = ref(props.historyItems);
62
+ const isShowDrawer = ref(false);
63
+ const inputRef = ref();
64
+
65
+ const isShowClearIcon = computed(() => {
66
+ return (!lePadV.value && isShowDrawer.value) || (lePadV.value && searchInput.value);
67
+ });
68
+
69
+ watch(
70
+ () => props.modelValue,
71
+ (val) => {
72
+ if (searchInput.value !== val) {
73
+ searchInput.value = val;
74
+ }
75
+ }
76
+ );
77
+
78
+ watch(
79
+ () => searchInput.value,
80
+ (val) => {
81
+ emit('update:modelValue', val);
82
+ }
83
+ );
84
+
85
+ watch(
86
+ () => props.historyItems,
87
+ (val) => {
88
+ if (searchHistoryItems.value !== val) {
89
+ searchHistoryItems.value = val;
90
+ }
91
+ }
92
+ );
93
+
94
+ watch(
95
+ () => searchHistoryItems.value,
96
+ (val) => {
97
+ emit('update:historyItems', val);
98
+ }
99
+ );
100
+
101
+ onMounted(() => {
102
+ if (props.storeHistory && props.storageKey) {
103
+ try {
104
+ const history = JSON.parse(localStorage.getItem(props.storageKey) || '[]');
105
+ if (Array.isArray(history) && history.length) {
106
+ searchHistoryItems.value = Array.from(new Set([...searchHistoryItems.value, ...history]));
107
+ }
108
+ } catch {
109
+ // nothing
110
+ }
111
+ }
112
+ });
113
+
114
+ const onShowDrawer = () => {
115
+ isShowDrawer.value = true;
116
+ };
117
+
118
+ const onSearch = () => {
119
+ const input = searchInput.value.trim();
120
+ if (!input) {
121
+ return;
122
+ }
123
+
124
+ isShowDrawer.value = false;
125
+ searchHistoryItems.value.unshift(input);
126
+ searchHistoryItems.value = Array.from(new Set(searchHistoryItems.value));
127
+ if (searchHistoryItems.value.length > props.maxHistoryCount) {
128
+ searchHistoryItems.value.pop();
129
+ }
130
+
131
+ if (props.storeHistory && props.storeHistory) {
132
+ localStorage.setItem(props.storageKey, JSON.stringify(searchHistoryItems.value));
133
+ }
134
+ emit('search', input);
135
+
136
+ if (props.searchUrl) {
137
+ window.open(props.searchUrl + input, props.searchUrlOpenBlank ? '_blank' : '_self', 'noopener noreferrer');
138
+ }
139
+ };
140
+
141
+ const onClear = () => {
142
+ searchInput.value = '';
143
+ emit('clear');
144
+ if (!lePadV.value) {
145
+ isShowDrawer.value = false;
146
+ }
147
+ };
148
+
149
+ const onDeleteHistory = () => {
150
+ const history = [...searchHistoryItems.value];
151
+ searchHistoryItems.value = [];
152
+ if (props.storeHistory && props.storeHistory) {
153
+ localStorage.removeItem(props.storageKey);
154
+ }
155
+
156
+ emit('delete-history', history);
157
+ };
158
+
159
+ const onDeleteHistoryItem = (val: string) => {
160
+ searchHistoryItems.value = searchHistoryItems.value.filter((item) => item !== val);
161
+ if (props.storeHistory && props.storeHistory) {
162
+ if (searchHistoryItems.value.length) {
163
+ localStorage.setItem(props.storageKey, JSON.stringify(searchHistoryItems.value));
164
+ } else {
165
+ localStorage.removeItem(props.storageKey);
166
+ }
167
+ }
168
+
169
+ emit('delete-history-item', val);
170
+ };
171
+
172
+ const onWordSearch = (val: string) => {
173
+ searchInput.value = val;
174
+ onSearch();
175
+ };
176
+
177
+ const onBack = () => {
178
+ searchInput.value = '';
179
+ isShowDrawer.value = false;
180
+ };
181
+
182
+ const posWrapper = ref();
183
+ onClickOutside(posWrapper, onClear);
184
+ </script>
185
+
186
+ <template>
187
+ <div class="o-header-search">
188
+ <div
189
+ ref="posWrapper"
190
+ :class="{
191
+ 'o-header-search-input-pc-wrapper': !lePadV,
192
+ 'o-header-search-input-pc-wrapper-left': !lePadV && expandDirection === 'left',
193
+ 'o-header-search-input-pc-wrapper-right': !lePadV && expandDirection === 'right',
194
+ 'o-header-search-input-mobile-wrapper': lePadV,
195
+ focus: isShowDrawer,
196
+ }"
197
+ >
198
+ <div class="o-header-search-input-wrapper" :class="{ focus: isShowDrawer }">
199
+ <OIcon v-if="lePadV && isShowDrawer" class="o-header-search-icon" @click="onBack">
200
+ <IconBack />
201
+ </OIcon>
202
+
203
+ <OInput
204
+ ref="inputRef"
205
+ v-model="searchInput"
206
+ class="o-header-search-input"
207
+ :placeholder="isShowDrawer ? expandedPlaceholder ?? t('search.expandedPlaceholder') : placeholder ?? t('search.placeholder')"
208
+ @focus="onShowDrawer"
209
+ @keyup.enter="onSearch"
210
+ >
211
+ <template #prefix>
212
+ <slot name="input-prefix">
213
+ <OIcon class="o-header-search-icon">
214
+ <IconSearch />
215
+ </OIcon>
216
+ </slot>
217
+ </template>
218
+
219
+ <template #suffix>
220
+ <slot name="input-suffix">
221
+ <OIcon v-if="clearable && isShowClearIcon" class="o-header-search-icon close" @click="onClear">
222
+ <IconClose />
223
+ </OIcon>
224
+ </slot>
225
+ </template>
226
+ </OInput>
227
+
228
+ <span v-if="lePadV && isShowDrawer" class="o-header-search-text" @click="onSearch">{{ searchTextMobile ?? t('search') }}</span>
229
+ </div>
230
+
231
+ <div v-show="isShowDrawer" class="o-header-search-drawer">
232
+ <slot name="drawer" :recommend-items="recommendItems" :history-items="searchHistoryItems" :hot-items="hotItems">
233
+ <!-- 搜索推荐 -->
234
+ <div v-if="recommendItems.length" class="o-header-search-recommend-container">
235
+ <slot name="recommend-header" :recommend="recommendItems" />
236
+ <slot name="recommend-content" :recommend="recommendItems">
237
+ <div v-for="item in recommendItems" class="o-header-search-recommend-item" :key="item" @click="onWordSearch(item)">
238
+ {{ item }}
239
+ </div>
240
+ </slot>
241
+ </div>
242
+
243
+ <!-- 历史记录 -->
244
+ <div v-else-if="searchHistoryItems.length" class="o-header-search-history-container">
245
+ <slot name="history-header" :history="searchHistoryItems">
246
+ <div class="o-header-search-history-header">
247
+ <span class="o-header-search-history-header-title">{{ historyTitle ?? t('search.history') }}</span>
248
+ <OIcon class="o-header-search-icon" @click="onDeleteHistory">
249
+ <IconDeleteAll />
250
+ </OIcon>
251
+ </div>
252
+ </slot>
253
+
254
+ <slot name="history-content" :history="searchHistoryItems">
255
+ <div class="o-header-search-history-item-container">
256
+ <div v-for="item in searchHistoryItems" :key="item" class="o-header-search-history-item" @click="onWordSearch(item)">
257
+ <span class="o-header-search-history-item-text">{{ item }}</span>
258
+ <OIcon class="o-header-search-history-item-icon" @click.stop="onDeleteHistoryItem(item)">
259
+ <IconDelete class="icon-delete" />
260
+ </OIcon>
261
+ </div>
262
+ </div>
263
+ </slot>
264
+ </div>
265
+
266
+ <ODivider v-if="(recommendItems.length || searchHistoryItems.length) && hotItems.length" class="o-header-search-drawer-divider" />
267
+
268
+ <!-- 热门搜索 -->
269
+ <div v-if="hotItems.length" class="o-header-search-hot-container">
270
+ <slot name="hot-header" :hot="hotItems">
271
+ <div class="o-header-search-hot-header">{{ hotTitle ?? t('search.hot') }}</div>
272
+ </slot>
273
+
274
+ <slot name="hot-content" :hot="hotItems">
275
+ <div class="o-header-search-hot-item-container">
276
+ <div v-for="item in hotItems" :key="item" class="o-header-search-hot-item" @click="onWordSearch(item)">{{ item }}</div>
277
+ </div>
278
+ </slot>
279
+ </div>
280
+ </slot>
281
+ </div>
282
+ </div>
283
+
284
+ <OIcon v-if="lePadV" class="o-header-search-icon-mobile" @click="onShowDrawer">
285
+ <IconSearch />
286
+ </OIcon>
287
+ </div>
288
+ </template>
289
+
290
+ <style lang="scss" scoped>
291
+ .o-header-search {
292
+ position: relative;
293
+ width: 160px;
294
+ height: 32px;
295
+
296
+ @include respond-to('<=laptop') {
297
+ width: 120px;
298
+ }
299
+
300
+ @media screen and (max-width: 1080px) {
301
+ width: 24px;
302
+ height: 24px;
303
+ }
304
+ }
305
+
306
+ .o-header-search-icon {
307
+ cursor: pointer;
308
+ color: var(--o-color-info1);
309
+ @include h4;
310
+
311
+ @include respond-to('<=pad_v') {
312
+ font-size: 20px;
313
+ }
314
+
315
+ .close {
316
+ @include x-svg-hover;
317
+ }
318
+ }
319
+
320
+ .o-header-search-icon-mobile {
321
+ font-size: 24px;
322
+ line-height: 28px;
323
+ color: var(--o-color-info1);
324
+ cursor: pointer;
325
+ display: none;
326
+
327
+ @include respond-to('<=pad_v') {
328
+ display: block;
329
+ }
330
+ }
331
+
332
+ .o-header-search-input-pc-wrapper {
333
+ position: absolute;
334
+ right: 0;
335
+ top: 0;
336
+ width: fit-content;
337
+ background-color: var(--o-color-fill2);
338
+ z-index: 100;
339
+ }
340
+
341
+ .o-header-search-input-pc-wrapper-left {
342
+ right: 0;
343
+ }
344
+
345
+ .o-header-search-input-pc-wrapper-right {
346
+ left: 0;
347
+ }
348
+
349
+ .o-header-search-input-pc-wrapper.focus {
350
+ box-shadow: var(--o-shadow-2);
351
+ top: calc(-1 * var(--o-gap-4));
352
+ }
353
+
354
+ .o-header-search-input-mobile-wrapper {
355
+ display: none;
356
+ }
357
+
358
+ .o-header-search-input-mobile-wrapper.focus {
359
+ position: fixed;
360
+ top: 0;
361
+ right: 0;
362
+ bottom: 0;
363
+ left: 0;
364
+ display: block;
365
+ height: 100vh;
366
+ background-color: var(--o-color-fill2);
367
+ z-index: 100;
368
+ overflow: hidden;
369
+ }
370
+
371
+ .o-header-search-input-wrapper {
372
+ .o-header-search-input {
373
+ width: 160px;
374
+ transition: width var(--o-easing-standard-in) var(--o-duration-m2);
375
+
376
+ @include respond-to('<=laptop') {
377
+ width: 120px;
378
+ }
379
+ }
380
+ }
381
+
382
+ .o-header-search-input-wrapper.focus {
383
+ padding: var(--o-gap-4);
384
+
385
+ @include respond-to('<=pad_v') {
386
+ display: flex;
387
+ align-items: center;
388
+ gap: var(--o-gap-4);
389
+ padding: 10px var(--o-gap-4) var(--o-gap-4) var(--o-gap-4);
390
+ }
391
+
392
+ .o-header-search-input {
393
+ width: 480px;
394
+
395
+ @include respond-to('<=laptop') {
396
+ width: 240px;
397
+ }
398
+
399
+ @include respond-to('<=pad_v') {
400
+ flex: 1;
401
+ }
402
+ }
403
+ }
404
+
405
+ .o-header-search-icon.close {
406
+ @include x-svg-hover;
407
+ }
408
+
409
+ .o-header-search-drawer {
410
+ position: absolute;
411
+ width: 100%;
412
+ padding: var(--o-gap-5);
413
+ padding-top: var(--o-gap-2);
414
+ background-color: var(--o-color-fill2);
415
+ box-shadow: var(--o-shadow-2);
416
+
417
+ @include respond-to('<=pad_v') {
418
+ position: static;
419
+ height: calc(100vh - 50px);
420
+ padding-top: 0;
421
+ overflow-y: auto;
422
+ box-shadow: unset;
423
+ }
424
+ }
425
+
426
+ .o-header-search-drawer::before {
427
+ content: '';
428
+ position: absolute;
429
+ left: 0;
430
+ right: 0;
431
+ top: -14px;
432
+ height: 14px;
433
+ background-color: var(--o-color-fill2);
434
+ box-shadow: unset;
435
+
436
+ @include respond-to('<=laptop') {
437
+ top: -10px;
438
+ height: 10px;
439
+ }
440
+
441
+ @include respond-to('<=pad') {
442
+ top: -8px;
443
+ height: 8px;
444
+ }
445
+
446
+ @include respond-to('<=pad_v') {
447
+ display: none;
448
+ }
449
+ }
450
+
451
+ .o-header-search-recommend-container {
452
+ color: var(--o-color-info1);
453
+ margin-bottom: var(--o-gap-3);
454
+ }
455
+
456
+ .o-header-search-recommend-item {
457
+ cursor: pointer;
458
+ @include tip2;
459
+
460
+ @include hover {
461
+ color: var(--o-color-primary1);
462
+ }
463
+
464
+ @include respond-to('<=pad_v') {
465
+ font-size: 12px;
466
+ line-height: 18px;
467
+ }
468
+
469
+ & + & {
470
+ margin-top: var(--o-gap-3);
471
+ }
472
+ }
473
+
474
+ .o-header-search-history-container {
475
+ @include respond-to('<=pad_v') {
476
+ margin-bottom: var(--o-gap-5);
477
+ }
478
+ }
479
+
480
+ .o-header-search-history-header {
481
+ display: flex;
482
+ align-items: center;
483
+ justify-content: space-between;
484
+ }
485
+
486
+ .o-header-search-history-header-title {
487
+ @include tip2;
488
+ color: var(--o-color-info3);
489
+
490
+ @include respond-to('<=pad_v') {
491
+ @include text2;
492
+ color: var(--o-color-info1);
493
+ }
494
+ }
495
+
496
+ .o-header-search-history-item-container {
497
+ display: flex;
498
+ gap: 8px;
499
+ flex-wrap: wrap;
500
+ margin-top: var(--o-gap-2);
501
+ }
502
+
503
+ .o-header-search-history-item-icon {
504
+ position: absolute;
505
+ right: -8px;
506
+ top: -8px;
507
+ display: none;
508
+ align-items: center;
509
+ justify-content: center;
510
+ width: 16px;
511
+ height: 16px;
512
+ border-radius: 50%;
513
+ background-color: rgb(var(--o-mixedgray-9));
514
+
515
+ .icon-delete {
516
+ height: 16px;
517
+ width: 16px;
518
+ color: var(--o-color-white);
519
+ }
520
+ }
521
+
522
+ .o-header-search-history-item {
523
+ position: relative;
524
+ display: flex;
525
+ align-items: center;
526
+ max-width: 224px;
527
+ height: 24px;
528
+ padding: 0 var(--o-gap-3);
529
+ background-color: var(--o-color-fill3);
530
+ border-radius: var(--o-radius-xs);
531
+ cursor: pointer;
532
+
533
+ @include hover {
534
+ background-color: var(--o-color-control2-light);
535
+ color: var(--o-color-primary1);
536
+
537
+ .o-header-search-history-item-icon {
538
+ display: flex;
539
+ }
540
+ }
541
+ }
542
+
543
+ .o-header-search-history-item-text {
544
+ max-width: 200px;
545
+ overflow: hidden;
546
+ text-overflow: ellipsis;
547
+ white-space: nowrap;
548
+ @include tip2;
549
+
550
+ @include respond-to('<=pad_v') {
551
+ @include text1;
552
+ }
553
+ }
554
+
555
+ .o-header-search-drawer-divider {
556
+ --o-divider-gap: var(--o-gap-4);
557
+
558
+ @include respond-to('<=pad_v') {
559
+ display: none;
560
+ }
561
+ }
562
+
563
+ .o-header-search-hot-header {
564
+ color: var(--o-color-info3);
565
+ @include tip2;
566
+
567
+ @include respond-to('<=pad_v') {
568
+ margin-bottom: var(--o-gap-3);
569
+ @include text2;
570
+ }
571
+ }
572
+
573
+ .o-header-search-hot-item-container {
574
+ display: flex;
575
+ flex-wrap: wrap;
576
+ gap: var(--o-gap-4);
577
+ margin-top: var(--o-gap-3);
578
+ @include tip2;
579
+
580
+ @include respond-to('<=pad_v') {
581
+ flex-direction: column;
582
+ gap: 12px;
583
+ font-size: 12px;
584
+ line-height: 18px;
585
+ }
586
+ }
587
+
588
+ .o-header-search-hot-item {
589
+ color: var(--o-color-info1);
590
+ cursor: pointer;
591
+
592
+ @include hover {
593
+ color: var(--o-color-primary1);
594
+ }
595
+ }
596
+
597
+ .o-header-search-text {
598
+ font-size: 16px;
599
+ line-height: 24px;
600
+ }
601
+ </style>
@@ -0,0 +1,32 @@
1
+ <script lang="ts" setup>
2
+ import { computed, provide, reactive } from 'vue';
3
+
4
+ import { OConfigProvider } from '@opensig/opendesign';
5
+ import zhCN from '@opensig/opendesign/es/locale/lang/zh-cn';
6
+ import enUS from '@opensig/opendesign/es/locale/lang/en-us';
7
+
8
+ import { configProviderInjectKey } from '@/shared/provide';
9
+
10
+ export interface OPlusConfigProviderPropsT {
11
+ locale: 'zh' | 'en';
12
+ theme: 'light' | 'dark';
13
+ }
14
+
15
+ const props = withDefaults(defineProps<OPlusConfigProviderPropsT>(), {
16
+ lang: 'zh',
17
+ theme: 'light',
18
+ });
19
+
20
+ const globalConfig = reactive({
21
+ locale: computed(() => props.locale),
22
+ theme: computed(() => props.theme),
23
+ });
24
+
25
+ provide(configProviderInjectKey, globalConfig);
26
+ </script>
27
+
28
+ <template>
29
+ <OConfigProvider :locale="locale === 'zh' ? zhCN : enUS">
30
+ <slot />
31
+ </OConfigProvider>
32
+ </template>