@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,178 @@
1
+ <script setup lang="ts">
2
+ import { isArray, OLink, OIcon } from '@opensig/opendesign';
3
+ import IconChevronRight from '~icons/components/icon-chevron-right.svg';
4
+
5
+ interface SectionPropsT {
6
+ title?: string | Array<string>;
7
+ subtitle?: string;
8
+ full?: boolean;
9
+ headerJustifyCenter?: boolean;
10
+ footer?: string;
11
+ footerHref?: string;
12
+ }
13
+
14
+ const props = withDefaults(defineProps<SectionPropsT>(), {
15
+ title: undefined,
16
+ subtitle: undefined,
17
+ full: false,
18
+ headerJustifyCenter: true,
19
+ footer: undefined,
20
+ footerHref: undefined,
21
+ });
22
+ </script>
23
+
24
+ <template>
25
+ <div class="app-section" :class="{ 'is-full': props.full }">
26
+ <div class="section-wrapper">
27
+ <slot name="main">
28
+ <!-- header -->
29
+ <div v-if="$slots.header || props.title || props.subtitle" class="section-header" :class="{ 'is-left': !props.headerJustifyCenter }">
30
+ <slot name="header">
31
+ <template v-if="isArray(props.title)">
32
+ <h2 v-for="item in props.title" :key="item" class="section-title">
33
+ {{ item }}
34
+ </h2>
35
+ </template>
36
+ <h2 v-else-if="$slots.title || props.title" class="section-title">
37
+ <slot name="title">
38
+ {{ props.title }}
39
+ </slot>
40
+ </h2>
41
+ <p v-if="$slots.subtitle || props.subtitle" class="section-subtitle">
42
+ <slot name="subtitle">
43
+ {{ props.subtitle }}
44
+ </slot>
45
+ </p>
46
+ </slot>
47
+ </div>
48
+
49
+ <!-- body -->
50
+ <div v-if="$slots.default" class="section-body">
51
+ <slot></slot>
52
+ </div>
53
+
54
+ <!-- footer -->
55
+ <div v-if="$slots.footer || props.footer" class="section-footer">
56
+ <slot name="footer">
57
+ <OLink :href="props.footerHref" target="_blank">
58
+ {{ props.footer }}
59
+ <template #suffix>
60
+ <OIcon class="footer-icon"><IconChevronRight /> </OIcon>
61
+ </template>
62
+ </OLink>
63
+ </slot>
64
+ </div>
65
+ </slot>
66
+ </div>
67
+ </div>
68
+ </template>
69
+
70
+ <style lang="scss" scoped>
71
+ .app-section {
72
+ --o-gap-section: var(--o-gap-7);
73
+ .section-wrapper {
74
+ margin: var(--o-gap-section) auto 0;
75
+ }
76
+
77
+ &.is-full {
78
+ .section-body {
79
+ max-width: 100%;
80
+ width: 100%;
81
+ padding: 0;
82
+ }
83
+ }
84
+
85
+ &:last-child {
86
+ .section-wrapper {
87
+ padding-bottom: var(--o-gap-section);
88
+ }
89
+ }
90
+
91
+ .section-header {
92
+ &.is-left {
93
+ .section-title,
94
+ .section-subtitle {
95
+ justify-content: start;
96
+ }
97
+ }
98
+ }
99
+
100
+ .section-title {
101
+ max-width: var(--layout-content-max-width);
102
+ padding: 0 var(--layout-content-padding);
103
+ margin: 0 auto;
104
+
105
+ display: flex;
106
+ justify-content: center;
107
+ color: var(--o-color-info1);
108
+ text-align: center;
109
+ @include display3;
110
+ font-weight: 500;
111
+ }
112
+
113
+ .section-subtitle {
114
+ max-width: var(--layout-content-max-width);
115
+ padding: 0 var(--layout-content-padding);
116
+ margin: 0 auto;
117
+
118
+ display: flex;
119
+ justify-content: center;
120
+ margin-top: 12px;
121
+ color: var(--o-color-info2);
122
+ @include text1;
123
+
124
+ @include respond-to('pad-laptop') {
125
+ margin-top: 8px;
126
+ }
127
+
128
+ @include respond-to('phone') {
129
+ margin-top: 12px;
130
+ text-align: center;
131
+ }
132
+ }
133
+
134
+ .section-body {
135
+ max-width: var(--layout-content-max-width);
136
+ padding: 0 var(--layout-content-padding);
137
+ margin: 0 auto;
138
+
139
+ margin-top: var(--o-gap-7);
140
+ }
141
+
142
+ .section-footer {
143
+ max-width: var(--layout-content-max-width);
144
+ padding: 0 var(--layout-content-padding);
145
+ margin: 0 auto;
146
+ color: var(--o-color-info1);
147
+
148
+ display: flex;
149
+ justify-content: center;
150
+ @include text1;
151
+
152
+ margin-top: 32px;
153
+
154
+ :deep(.o-btn) {
155
+ border-radius: var(--btn-height);
156
+ }
157
+
158
+ @include respond-to('<=laptop') {
159
+ margin-top: 16px;
160
+ }
161
+
162
+ @include respond-to('phone') {
163
+ margin-top: 12px;
164
+ }
165
+
166
+ &:hover {
167
+ .footer-icon {
168
+ fill: var(--link-color-active);
169
+ }
170
+ }
171
+ }
172
+
173
+ .footer-icon {
174
+ font-size: 16px;
175
+ height: 24px;
176
+ }
177
+ }
178
+ </style>
@@ -0,0 +1,108 @@
1
+ <script lang="ts" setup>
2
+ import { Component, computed } from 'vue';
3
+ import { OIcon, OSwitch } from '@opensig/opendesign';
4
+ import { useScreen } from '@opendesign-plus/composables';
5
+
6
+ import IconSun from '~icons/components/icon-sun.svg';
7
+ import IconMoon from '~icons/components/icon-moon.svg';
8
+
9
+ export interface OThemeSwitcherPropsT {
10
+ theme?: string;
11
+ type?: 'auto' | 'common' | 'mobile';
12
+ lightValue?: string;
13
+ darkValue?: string;
14
+ lightIcon?: Component;
15
+ darkIcon?: Component;
16
+ }
17
+
18
+ export interface OThemeSwitcherEmitsT {
19
+ (e: 'update:theme', value: string): void;
20
+ (e: 'change', val: string): void;
21
+ }
22
+
23
+ const props = withDefaults(defineProps<OThemeSwitcherPropsT>(), {
24
+ theme: 'light',
25
+ type: 'auto',
26
+ lightValue: 'light',
27
+ darkValue: 'dark',
28
+ lightIcon: IconSun,
29
+ darkIcon: IconMoon,
30
+ });
31
+
32
+ const emit = defineEmits<OThemeSwitcherEmitsT>();
33
+
34
+ const { gtPhone } = useScreen();
35
+
36
+ const switchVal = computed({
37
+ get() {
38
+ return props.theme;
39
+ },
40
+ set(val) {
41
+ emit('update:theme', val);
42
+ emit('change', val);
43
+ },
44
+ });
45
+
46
+ const isCommon = computed(() => {
47
+ return props.type === 'common' || (props.type === 'auto' && gtPhone.value);
48
+ });
49
+
50
+ const toggleTheme = () => {
51
+ switchVal.value = switchVal.value === props.lightValue ? props.darkValue : props.lightValue;
52
+ };
53
+ </script>
54
+
55
+ <template>
56
+ <div class="o-theme-switcher">
57
+ <div v-if="isCommon" class="o-theme-switcher-common" @click="toggleTheme">
58
+ <OIcon class="o-theme-icon">
59
+ <IconMoon v-if="switchVal === lightValue" />
60
+ <IconSun v-else />
61
+ </OIcon>
62
+ </div>
63
+
64
+ <div v-else class="o-theme-switcher-mobile">
65
+ <OSwitch v-model="switchVal" class="o-theme-switch" :checked-value="darkValue" :unchecked-value="lightValue">
66
+ <template #on>
67
+ <OIcon class="o-theme-icon">
68
+ <IconSun />
69
+ </OIcon>
70
+ </template>
71
+ <template #off>
72
+ <OIcon class="o-theme-icon">
73
+ <IconMoon />
74
+ </OIcon>
75
+ </template>
76
+ </OSwitch>
77
+ </div>
78
+ </div>
79
+ </template>
80
+
81
+ <style lang="scss" scoped>
82
+ .o-theme-switcher-common {
83
+ cursor: pointer;
84
+ width: 20px;
85
+ height: 20px;
86
+ display: flex;
87
+ align-items: center;
88
+
89
+ .o-theme-icon {
90
+ font-size: 24px;
91
+ color: var(--o-color-info1);
92
+
93
+ @include hover {
94
+ color: var(--o-color-primary1);
95
+ }
96
+ }
97
+ }
98
+
99
+ .o-theme-switcher-mobile {
100
+ .o-theme-switch {
101
+ background-color: var(--o-color-control1-light);
102
+
103
+ .o-theme-icon {
104
+ color: var(--o-color-white);
105
+ }
106
+ }
107
+ }
108
+ </style>
@@ -0,0 +1,21 @@
1
+ import { defineComponent, onMounted, ref, h, resolveComponent } from 'vue';
2
+
3
+ const fallback = (slots: any) => {
4
+ const show = ref(false);
5
+
6
+ onMounted(() => {
7
+ show.value = true;
8
+ });
9
+
10
+ return () => (show.value && slots.default ? slots.default() : null);
11
+ };
12
+
13
+ export default defineComponent({
14
+ setup(_, { slots }) {
15
+ const BuiltIn = resolveComponent('ClientOnly');
16
+ if (BuiltIn && typeof BuiltIn !== 'string') {
17
+ return () => h(BuiltIn, null, { default: () => slots.default ? slots.default() : null });
18
+ }
19
+ return fallback(slots);
20
+ },
21
+ });
@@ -0,0 +1,85 @@
1
+ <script setup lang="ts">
2
+ import { isBoolean, isString, isUndefined } from '@opensig/opendesign';
3
+ import { computed } from 'vue';
4
+
5
+ const DEFAULT = Symbol('default');
6
+
7
+ interface ContentWrapperPropsT {
8
+ verticalPadding?: boolean | string | Array<string>;
9
+ }
10
+
11
+ const props = withDefaults(defineProps<ContentWrapperPropsT>(), {
12
+ verticalPadding: undefined,
13
+ });
14
+
15
+ const paddingTop = computed(() => {
16
+ if (!props.verticalPadding) {
17
+ return 0;
18
+ }
19
+
20
+ if (isBoolean(props.verticalPadding)) {
21
+ return DEFAULT;
22
+ } else if (isString(props.verticalPadding)) {
23
+ return props.verticalPadding;
24
+ } else {
25
+ return props.verticalPadding[0];
26
+ }
27
+ });
28
+
29
+ const paddingBottom = computed(() => {
30
+ if (!props.verticalPadding) {
31
+ return 0;
32
+ }
33
+
34
+ if (isBoolean(props.verticalPadding)) {
35
+ return DEFAULT;
36
+ } else if (isString(props.verticalPadding)) {
37
+ return props.verticalPadding;
38
+ } else {
39
+ return !isUndefined(props.verticalPadding[1]) ? props.verticalPadding[1] : props.verticalPadding[0];
40
+ }
41
+ });
42
+ </script>
43
+
44
+ <template>
45
+ <div
46
+ class="content-wrapper"
47
+ :style="{
48
+ '--content-wrapper-vertical-paddingTop': paddingTop === DEFAULT ? undefined : paddingTop,
49
+ '--content-wrapper-vertical-paddingBottom': paddingBottom === DEFAULT ? undefined : paddingBottom,
50
+ }"
51
+ >
52
+ <slot></slot>
53
+ </div>
54
+ </template>
55
+
56
+ <style lang="scss" scoped>
57
+ .content-wrapper {
58
+ --layout-content-max-width: 1544px;
59
+ --layout-content-padding: 64px;
60
+ --layout-header-height: 80px;
61
+
62
+ @include respond-to('<=laptop') {
63
+ --layout-content-max-width: 100%;
64
+ --layout-content-padding: 40px;
65
+ }
66
+
67
+ @include respond-to('<=pad') {
68
+ --layout-content-padding: 32px;
69
+ }
70
+
71
+ @include respond-to('phone') {
72
+ --layout-content-padding: 24px;
73
+ }
74
+
75
+ max-width: var(--layout-content-max-width);
76
+ padding-left: var(--layout-content-padding);
77
+ padding-right: var(--layout-content-padding);
78
+ margin: 0 auto;
79
+
80
+ --content-wrapper-vertical-paddingTop: 72px;
81
+ --content-wrapper-vertical-paddingBottom: 72px;
82
+ padding-top: var(--content-wrapper-vertical-paddingTop);
83
+ padding-bottom: var(--content-wrapper-vertical-paddingBottom);
84
+ }
85
+ </style>
@@ -0,0 +1,265 @@
1
+ <script setup lang="ts">
2
+ import { onMounted, type PropType } from 'vue';
3
+ import { OButton } from '@opensig/opendesign';
4
+
5
+ import AOS from 'aos';
6
+
7
+ import ContentWrapper from './ContentWrapper.vue';
8
+
9
+ defineProps({
10
+ backgroundImage: {
11
+ type: String,
12
+ default: '',
13
+ },
14
+ title: {
15
+ type: String,
16
+ default: '',
17
+ },
18
+ subtitle: {
19
+ type: String,
20
+ default: '',
21
+ },
22
+ href: {
23
+ type: String,
24
+ default: '',
25
+ },
26
+ text: {
27
+ type: String,
28
+ default: '',
29
+ },
30
+ // 风格
31
+ theme: {
32
+ type: String as PropType<'light' | 'dark'>,
33
+ default: 'light',
34
+ },
35
+ // 指定在何处显示链接的资源
36
+ target: {
37
+ type: String,
38
+ default: '_blank',
39
+ },
40
+ size: {
41
+ type: String as PropType<'small' | 'medium' | 'large'>,
42
+ default: 'medium',
43
+ },
44
+ });
45
+
46
+ onMounted(() => {
47
+ AOS.init({
48
+ duration: 800,
49
+ });
50
+ });
51
+ </script>
52
+
53
+ <template>
54
+ <div class="banner-content" :class="`banner-${size}`">
55
+ <div class="banner-bg" :style="{ backgroundImage: `url(${backgroundImage})` }"></div>
56
+ <ContentWrapper class="banner-text">
57
+ <div class="banner-text-content">
58
+ <p v-if="title" class="banner-title" data-aos="fade-up">{{ title }}</p>
59
+ <p v-if="subtitle" class="banner-subtitle" data-aos="fade-up">
60
+ {{ subtitle }}
61
+ </p>
62
+ <OButton v-if="href" variant="outline" color="primary" size="medium" :href="href" :target="target"
63
+ class="learn-btn">
64
+ <span>{{ text }}</span>
65
+ </OButton>
66
+ </div>
67
+ </ContentWrapper>
68
+ </div>
69
+ </template>
70
+
71
+ <style lang="scss">
72
+ .banner-content {
73
+ width: 100%;
74
+ position: relative;
75
+ }
76
+
77
+ .banner-bg {
78
+ height: 100%;
79
+ margin: 0 auto;
80
+ background-repeat: no-repeat;
81
+ background-size: cover;
82
+ background-position: center;
83
+ }
84
+
85
+ .banner-text {
86
+ position: absolute;
87
+ width: 100%;
88
+ height: 100%;
89
+ top: 0;
90
+ left: 0;
91
+ }
92
+
93
+ .banner-text-content {
94
+ height: 100%;
95
+ }
96
+
97
+ .learn-btn {
98
+ margin-top: 24px;
99
+ }
100
+
101
+ .banner-small {
102
+ height: 280px;
103
+
104
+ .banner-title {
105
+ color: var(--o-color-info1);
106
+ font-weight: 500;
107
+ padding-top: 48px;
108
+ @include display2;
109
+ }
110
+
111
+ .banner-subtitle {
112
+ color: var(--o-color-info1);
113
+ margin-top: 8px;
114
+ width: 60%;
115
+ @include text2;
116
+ }
117
+
118
+ @media (min-width: 1201px) and (max-width: 1680px) {
119
+ height: 220px;
120
+
121
+ .banner-title {
122
+ padding-top: 40px;
123
+ @include display3;
124
+ }
125
+
126
+ .banner-subtitle {
127
+ @include text1;
128
+ }
129
+ }
130
+
131
+ @include respond-to('pad_h') {
132
+ height: 180px;
133
+
134
+ .banner-title {
135
+ padding-top: 32px;
136
+ @include h1;
137
+ }
138
+
139
+ .banner-subtitle {
140
+ @include tip1;
141
+ }
142
+ }
143
+
144
+ @include respond-to('<=pad_v') {
145
+ display: none;
146
+ }
147
+ }
148
+
149
+ .banner-medium {
150
+ height: 360px;
151
+
152
+ .banner-title {
153
+ color: var(--o-color-info1);
154
+ font-weight: 500;
155
+ padding-top: 88px;
156
+ @include display2;
157
+ }
158
+
159
+ .banner-subtitle {
160
+ color: var(--o-color-info1);
161
+ margin-top: 8px;
162
+ width: 60%;
163
+ @include text2;
164
+ }
165
+
166
+ @media (min-width: 1201px) and (max-width: 1680px) {
167
+ height: 280px;
168
+
169
+ .banner-title {
170
+ padding-top: 64px;
171
+ @include display3;
172
+ }
173
+
174
+ .banner-subtitle {
175
+ @include text1;
176
+ }
177
+ }
178
+
179
+ @include respond-to('pad_h') {
180
+ height: 220px;
181
+
182
+ .banner-title {
183
+ padding-top: 48px;
184
+ @include h1;
185
+ }
186
+
187
+ .banner-subtitle {
188
+ @include tip1;
189
+ }
190
+ }
191
+
192
+ @include respond-to('<=pad_v') {
193
+ height: 120px;
194
+
195
+ .banner-title {
196
+ text-align: center;
197
+ padding-top: 48px;
198
+ @include h3;
199
+ }
200
+
201
+ .banner-subtitle {
202
+ display: none;
203
+ }
204
+ }
205
+ }
206
+
207
+ .banner-large {
208
+ height: 460px;
209
+
210
+ .banner-title {
211
+ color: var(--o-color-info1);
212
+ font-weight: 500;
213
+ padding-top: 124px;
214
+ @include display1;
215
+ }
216
+
217
+ .banner-subtitle {
218
+ color: var(--o-color-info1);
219
+ margin-top: 8px;
220
+ width: 60%;
221
+ @include h4;
222
+ }
223
+
224
+ @media (min-width: 1201px) and (max-width: 1680px) {
225
+ height: 400px;
226
+
227
+ .banner-title {
228
+ padding-top: 100px;
229
+ @include display2;
230
+ }
231
+
232
+ .banner-subtitle {
233
+ @include text2;
234
+ }
235
+ }
236
+
237
+ @include respond-to('pad_h') {
238
+ height: 320px;
239
+
240
+ .banner-title {
241
+ padding-top: 80px;
242
+ @include display3;
243
+ }
244
+
245
+ .banner-subtitle {
246
+ @include text1;
247
+ }
248
+ }
249
+
250
+ @include respond-to('<=pad_v') {
251
+ height: 184px;
252
+
253
+ .banner-title {
254
+ text-align: center;
255
+ padding-top: 48px;
256
+ @include h3;
257
+ }
258
+
259
+ .banner-subtitle {
260
+ text-align: center;
261
+ @include tip2;
262
+ }
263
+ }
264
+ }
265
+ </style>