v-uni-app-ui 1.0.0 → 1.0.4

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 (86) hide show
  1. package/README.md +147 -0
  2. package/components/config/css/basic.scss +19 -0
  3. package/components/config/interface/basic-type.js +16 -0
  4. package/components/config/interface/components-interface.ts +0 -0
  5. package/components/config/interface/monitor/components/input-monitor.js +0 -0
  6. package/components/config/interface/monitor/property-monitor.ts +136 -0
  7. package/components/config/interface/props/basic-props.ts +88 -0
  8. package/components/config/interface/props/components/button-props.ts +85 -0
  9. package/components/config/interface/props/components/input-props.ts +69 -0
  10. package/components/config/interface/props/props-tools.ts +64 -0
  11. package/components/config/style/basic.js +346 -0
  12. package/components/config/style/component-registry.js +142 -0
  13. package/components/config/style/components/button-style.js +160 -0
  14. package/components/config/style/components/input-style.js +98 -0
  15. package/components/config/style/components-style.js +622 -0
  16. package/components/config/style/property-mapper.js +377 -0
  17. package/components/config/style/pseudo-processor.js +213 -0
  18. package/components/config.js +123 -0
  19. package/components/icon/iconfont.css +87 -0
  20. package/components/icon/iconfont.js +1 -0
  21. package/components/icon/iconfont.json +135 -0
  22. package/components/icon/iconfont.ttf +0 -0
  23. package/components/icon/iconfont.woff +0 -0
  24. package/components/icon/iconfont.woff2 +0 -0
  25. package/components/layout/v-card/v-card.vue +108 -0
  26. package/components/layout/v-grid/v-grid.vue +162 -0
  27. package/components/layout/v-icon-grid/v-icon-grid.vue +195 -0
  28. package/components/layout/v-infinite-scroll/v-infinite-scroll.vue +172 -0
  29. package/components/layout/v-list/v-list.vue +43 -0
  30. package/components/layout/v-row/v-row.vue +142 -0
  31. package/components/layout/v-waterfall/v-waterfall.vue +79 -0
  32. package/components/model/compound/v-checkbox-group/v-checkbox-group.vue +96 -0
  33. package/components/model/compound/v-console/v-console.js +20 -0
  34. package/components/model/compound/v-console/v-console.vue +299 -0
  35. package/components/model/compound/v-date-time/v-date-time.vue +261 -0
  36. package/components/model/compound/v-dialog/v-dialog.vue +178 -0
  37. package/components/model/compound/v-drum-select-picker/v-drum-select-picker.vue +83 -0
  38. package/components/model/compound/v-form/v-form.vue +226 -0
  39. package/components/model/compound/v-form-item/v-form-item.vue +255 -0
  40. package/components/model/compound/v-image/v-image.vue +357 -0
  41. package/components/model/compound/v-input-desensitize/v-input-desensitize.vue +101 -0
  42. package/components/model/compound/v-page/v-page.vue +11 -0
  43. package/components/model/compound/v-pages/v-pages.vue +141 -0
  44. package/components/model/compound/v-picker-list/v-picker-list.vue +109 -0
  45. package/components/model/compound/v-popup/v-popup.vue +151 -0
  46. package/components/model/compound/v-radio-group/v-radio-group.vue +86 -0
  47. package/components/model/compound/v-select-picker/v-select-picker.vue +202 -0
  48. package/components/model/compound/v-series-picker-list/v-series-picker-list.vue +221 -0
  49. package/components/model/compound/v-series-select-picker/v-series-select-picker.vue +203 -0
  50. package/components/model/compound/v-switch/v-switch.vue +136 -0
  51. package/components/model/compound/v-tabs-page/v-tabs-page.vue +138 -0
  52. package/components/model/native/v-badge/v-badge.vue +143 -0
  53. package/components/model/native/v-button/v-button.vue +81 -0
  54. package/components/model/native/v-carousel/v-carousel.vue +138 -0
  55. package/components/model/native/v-checkbox/v-checkbox.vue +215 -0
  56. package/components/model/native/v-collapse/v-collapse.vue +190 -0
  57. package/components/model/native/v-header-navigation-bar/v-header-navigation-bar.vue +92 -0
  58. package/components/model/native/v-input/v-input.vue +163 -0
  59. package/components/model/native/v-input-code/v-input-code.vue +146 -0
  60. package/components/model/native/v-loading/v-loading.vue +206 -0
  61. package/components/model/native/v-menu/v-menu.vue +222 -0
  62. package/components/model/native/v-menu-slide/v-menu-slide.vue +364 -0
  63. package/components/model/native/v-min-loading/v-min-loading.vue +80 -0
  64. package/components/model/native/v-null/v-null.vue +97 -0
  65. package/components/model/native/v-overlay/v-overlay.vue +96 -0
  66. package/components/model/native/v-pull-up-refresh/v-pull-up-refresh.vue +157 -0
  67. package/components/model/native/v-radio/v-radio.vue +138 -0
  68. package/components/model/native/v-scroll-list/v-scroll-list.vue +169 -0
  69. package/components/model/native/v-steps/v-steps.vue +253 -0
  70. package/components/model/native/v-table/v-table.vue +203 -0
  71. package/components/model/native/v-tabs/v-tabs.vue +235 -0
  72. package/components/model/native/v-tag/v-tag.vue +206 -0
  73. package/components/model/native/v-text/v-text.vue +187 -0
  74. package/components/model/native/v-textarea/v-textarea.vue +178 -0
  75. package/components/model/native/v-title/v-title.vue +91 -0
  76. package/components/model/native/v-toast/info.png +0 -0
  77. package/components/model/native/v-toast/success.png +0 -0
  78. package/components/model/native/v-toast/v-toast.vue +198 -0
  79. package/components/model/native/v-toast/warn.png +0 -0
  80. package/components/model/native/v-upload-file-button/v-upload-file-button.vue +296 -0
  81. package/components/model/native/v-video/v-video.vue +175 -0
  82. package/components/model/native/v-window/v-window.vue +158 -0
  83. package/components/utils/event-modifiers.ts +139 -0
  84. package/components/utils/validator.ts +451 -0
  85. package/index.js +372 -0
  86. package/package.json +25 -93
@@ -0,0 +1,143 @@
1
+ <template>
2
+ <view :class="['v-badge', { 'v-badge--dot': dot }, `v-badge--size-${size}`, `v-badge--position-${position}`]" :style="badgeStyle">
3
+ <slot></slot>
4
+ <view v-if="!dot && (isShowContent)" class="v-badge-content">
5
+ {{ displayContent }}
6
+ </view>
7
+ </view>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { computed,inject } from 'vue';
12
+
13
+ /**
14
+ * v-badge 标徽
15
+ * value 双向绑定值
16
+ * dot 省略显示
17
+ * max 最大值
18
+ * color 标徽颜色
19
+ * size 标徽大小 默认值:medium 可选值small小、medium中、large大
20
+ * position 标徽位置 默认值:right 可选值left左、right右
21
+ */
22
+ const props = defineProps({
23
+ value: {
24
+ type: [Number, String],
25
+ default: 0
26
+ },
27
+ dot: {
28
+ type: Boolean,
29
+ default: false
30
+ },
31
+ max: {
32
+ type: Number,
33
+ default: 99
34
+ },
35
+ color: {
36
+ type: String,
37
+ default: '#ff5357'
38
+ },
39
+ fontColor: {
40
+ type: String,
41
+ default: '#fff'
42
+ },
43
+ size: {
44
+ type: String,
45
+ default: 'medium',
46
+ validator: (value: string) => {
47
+ return ['small', 'medium', 'large'].includes(value);
48
+ }
49
+ },
50
+ position: {
51
+ type: String,
52
+ default: 'right',
53
+ validator: (value: string) => {
54
+ return ['left', 'right'].includes(value);
55
+ }
56
+ }
57
+ });
58
+
59
+
60
+ const config = inject<any>('config');
61
+ const displayContent = computed(() => {
62
+ if (props.dot) return '';
63
+ if (props.max && props.value > props.max) {
64
+ return `${props.max}+`;
65
+ }
66
+ return props.value;
67
+ });
68
+
69
+ const isShowContent = computed(() => {
70
+ if (props.dot) return false;
71
+ if (typeof props.value === 'string') return props.value.length > 0;
72
+ return props.value > 0;
73
+ });
74
+
75
+ const badgeStyle = computed(() => {
76
+ return {
77
+ '--badge-color': props.color
78
+ };
79
+ });
80
+ </script>
81
+
82
+ <style lang="scss" scoped>
83
+ .v-badge {
84
+ position: relative;
85
+ display: inline-flex;
86
+ align-items: center;
87
+
88
+ .v-badge-content {
89
+ position: absolute;
90
+ top: -12rpx;
91
+ right: -12rpx;
92
+ background-color: var(--badge-color, #ff4500);
93
+ color: v-bind('fontColor');
94
+ border-radius: v-bind("config.borderRadius.circle");
95
+ padding: 0 8rpx;
96
+ font-size: v-bind("config.fontSize.hintText");
97
+ height: 30rpx;
98
+ line-height: 30rpx;
99
+ text-align: center;
100
+ min-width: 26rpx;
101
+ transform: scale(0.8);
102
+ }
103
+
104
+ &--dot::after {
105
+ content: '';
106
+ position: absolute;
107
+ top: -6rpx;
108
+ right: -6rpx;
109
+ width: 16rpx;
110
+ height: 16rpx;
111
+ background-color: var(--badge-color, #ff4500);
112
+ border-radius: 50%;
113
+ }
114
+
115
+ &--size-small .v-badge-content {
116
+ font-size: v-bind("config.fontSize.smallText");
117
+ height: 22rpx;
118
+ line-height: 22rpx;
119
+ min-width: 22rpx;
120
+ padding: 6rpx 12rpx;
121
+ transform: scale(0.7);
122
+ }
123
+
124
+ &--size-large .v-badge-content {
125
+ font-size: v-bind("config.fontSize.largeText");
126
+ height: 25rpx;
127
+ line-height: 25rpx;
128
+ min-width: 25px;
129
+ padding: 3rpx 8rpx;
130
+ transform: scale(0.9);
131
+ }
132
+
133
+ &--position-left .v-badge-content {
134
+ left: -12rpx;
135
+ right: auto;
136
+ }
137
+
138
+ &--position-left::after {
139
+ left: -12rpx;
140
+ right: auto;
141
+ }
142
+ }
143
+ </style>
@@ -0,0 +1,81 @@
1
+ <template>
2
+ <button
3
+ :id="props.id"
4
+ :class="computedClasses"
5
+ :disabled="props.disabled || props.loading"
6
+ :style="computedStyle"
7
+ :hover-start-time="props.hoverStartTime"
8
+ :hover-stay-time="props.hoverStayTime"
9
+ @click="handleClick"
10
+ @mouseenter="hover(true)"
11
+ @mouseleave="hover(false)"
12
+ @mousedown="active(true)"
13
+ @mouseup="active(false)"
14
+ >
15
+ <template v-if="props.loading">
16
+ <slot name="loading">
17
+ <view class="loading-icon"><view class="spinner"></view></view>
18
+ </slot>
19
+ </template>
20
+
21
+ <template v-if="props.disabled">
22
+ <slot name="disabled">
23
+ <slot />
24
+ </slot>
25
+ </template>
26
+
27
+ <template v-else>
28
+ <slot />
29
+ </template>
30
+ </button>
31
+ </template>
32
+
33
+ <script setup lang="ts">
34
+ import { onUnmounted } from 'vue';
35
+ import buttonProps from '@/components/config/interface/props/components/button-props';
36
+ import { useComponentStyle } from '@/components/config/style/components-style';
37
+ import { useDebounce, useCooldown } from '@/components/utils/event-modifiers.ts';
38
+ import { usePropertyMonitor } from '@/components/config/interface/monitor/property-monitor';
39
+ type TimerHandle = ReturnType<typeof setTimeout>;
40
+
41
+ const props = defineProps(buttonProps);
42
+ const { style: computedStyle, classes: computedClasses, hover, active } = useComponentStyle('button', props);
43
+ const emit = defineEmits<{
44
+ click: [event: MouseEvent];
45
+ countdown: [payload: { remaining: number; total: number }];
46
+ }>();
47
+
48
+ const {
49
+ debounce,
50
+ isPending: isDebouncing,
51
+ cancel
52
+ } = useDebounce(handleClick, {
53
+ wait: props.debounceTime || 0,
54
+ immediate: false
55
+ });
56
+
57
+ const { isCountingDown, start, stop } = useCooldown({
58
+ stabilizationTime: props.stabilizationTime,
59
+ degressionTime: props.degressionTime,
60
+ intervalUpdateTime: props.intervalUpdateTime,
61
+ resetOnClick: props.resetOnClick,
62
+ onCountdown: (payload) => emit('countdown', payload)
63
+ });
64
+
65
+ function handleClick(event: MouseEvent) {
66
+ if (props.disabled || props.loading || isCountingDown.value) return;
67
+ emit('click', event);
68
+ start();
69
+ }
70
+
71
+ onUnmounted(() => {
72
+ cancel();
73
+ stop();
74
+ });
75
+ </script>
76
+
77
+ <style lang="scss">
78
+ uni-button::after {
79
+ border: none;
80
+ }
81
+ </style>
@@ -0,0 +1,138 @@
1
+ <template>
2
+ <view class="carousel-box">
3
+ <!-- 左右箭头 -->
4
+ <view class="carousel-nav-buttons" v-show="isEndsButton">
5
+ <view class="carousel-nav-buttons-prev" @click="prevSlide">
6
+ <slot name="prev-button">
7
+ <view class="default-prev-button">←</view>
8
+ </slot>
9
+ </view>
10
+ <view class="carousel-nav-buttons-next" @click="nextSlide">
11
+ <slot name="next-button">
12
+ <view class="default-next-button">→</view>
13
+ </slot>
14
+ </view>
15
+ </view>
16
+
17
+ <!-- 关键改动 1:key 强制重建 -->
18
+ <swiper
19
+ :key="carouselKey"
20
+ :indicator-dots="indicatorDots"
21
+ :autoplay="autoplay"
22
+ :interval="interval"
23
+ :duration="duration"
24
+ :current="currentVal"
25
+ :circular="circular"
26
+ @change="onSwiperChange"
27
+ class="swiper-box"
28
+ >
29
+ <swiper-item v-for="(item, index) in items" :key="index" class="carousel-item">
30
+ <slot :name="'item-' + index" :item="item"></slot>
31
+ </swiper-item>
32
+ </swiper>
33
+ </view>
34
+ </template>
35
+
36
+ <script setup lang="ts">
37
+ import { ref, watch, inject } from 'vue';
38
+
39
+ const props = defineProps({
40
+ items: { type: Array, default: () => [] },
41
+ indicatorDots: { type: Boolean, default: true },
42
+ autoplay: { type: Boolean, default: true },
43
+ interval: { type: Number, default: 5000 },
44
+ duration: { type: Number, default: 400 },
45
+ current: { type: Number, default: 0 },
46
+ isEndsButton: { type: Boolean, default: false },
47
+ circular: { type: Boolean, default: true }
48
+ });
49
+
50
+ const emit = defineEmits(['update:current', 'change']);
51
+ const config = inject<any>('config');
52
+
53
+ const currentVal = ref(props.current);
54
+ const carouselKey = ref(0); // 关键改动 2:刷新 key
55
+
56
+ /* 双向绑定 current */
57
+ watch(
58
+ () => props.current,
59
+ (v) => (currentVal.value = v),
60
+ { immediate: true }
61
+ );
62
+ watch(currentVal, (v) => emit('update:current', v));
63
+
64
+ /* 关键改动 3:节流防止抽搐 */
65
+ let changing = false;
66
+ const onSwiperChange = (e: any) => {
67
+ if (changing) return;
68
+ changing = true;
69
+ const { current } = e.detail;
70
+ currentVal.value = current;
71
+ emit('change', current);
72
+ setTimeout(() => (changing = false), 150);
73
+ };
74
+
75
+ /* 手动切换 */
76
+ const prevSlide = () => {
77
+ const len = props.items.length;
78
+ currentVal.value = currentVal.value <= 0 ? len - 1 : currentVal.value - 1;
79
+ emit('change', currentVal.value);
80
+ };
81
+ const nextSlide = () => {
82
+ const len = props.items.length;
83
+ currentVal.value = currentVal.value >= len - 1 ? 0 : currentVal.value + 1;
84
+ emit('change', currentVal.value);
85
+ };
86
+ </script>
87
+
88
+ <style lang="scss" scoped>
89
+ .carousel-box {
90
+ width: 100%;
91
+ /* 关键改动 4:禁止百分比高度,用固定值 */
92
+ height: 560rpx;
93
+ position: relative;
94
+ }
95
+
96
+ .carousel-nav-buttons {
97
+ position: absolute;
98
+ width: 90%;
99
+ top: 50%;
100
+ transform: translateY(-50%);
101
+ display: flex;
102
+ justify-content: space-between;
103
+ padding: 0 10rpx;
104
+ z-index: 10;
105
+ }
106
+
107
+ .carousel-nav-buttons-prev,
108
+ .carousel-nav-buttons-next {
109
+ display: flex;
110
+ align-items: center;
111
+ justify-content: center;
112
+ width: 40rpx;
113
+ height: 40rpx;
114
+ border-radius: 50%;
115
+ background-color: rgba(255, 255, 255, 0.5);
116
+ cursor: pointer;
117
+ user-select: none;
118
+ }
119
+
120
+ .default-prev-button,
121
+ .default-next-button {
122
+ font-size: v-bind('config.fontSize.largeText');
123
+ color: v-bind('config.fontColor.mainText');
124
+ }
125
+
126
+ .swiper-box {
127
+ width: 100%;
128
+ height: 100%;
129
+ }
130
+
131
+ .carousel-item {
132
+ width: 100%;
133
+ height: 100%;
134
+ display: flex;
135
+ justify-content: center;
136
+ align-items: center;
137
+ }
138
+ </style>
@@ -0,0 +1,215 @@
1
+ <template>
2
+ <label :class="['v-checkbox', { 'v-checkbox--disabled': isDisabled, 'v-checkbox--checked': isChecked, 'v-checkbox--indeterminate': isIndeterminate }]" @click="handleChange">
3
+ <span class="v-checkbox-input">
4
+ <span v-if="isChecked" class="v-checkbox-inner"></span>
5
+ </span>
6
+ <span class="v-checkbox-label">
7
+ <slot>{{ item.label }}</slot>
8
+ </span>
9
+ </label>
10
+ </template>
11
+
12
+ <script setup lang="ts">
13
+ import { ref, watch, inject, computed } from 'vue';
14
+
15
+ interface CheckboxItem {
16
+ label: string;
17
+ value: string | number | IndeterminateValue;
18
+ }
19
+
20
+ interface IndeterminateValue {
21
+ S: string | number | null;
22
+ A: string | number | null;
23
+ M: string | number | null;
24
+ }
25
+
26
+ const props = defineProps({
27
+ value: {
28
+ type: Array,
29
+ default: () => []
30
+ },
31
+ item: {
32
+ type: Object as () => CheckboxItem,
33
+ required: true
34
+ },
35
+ disabled: {
36
+ type: Boolean,
37
+ default: false
38
+ },
39
+ indeterminate: {
40
+ type: Boolean,
41
+ default: false
42
+ }
43
+ });
44
+
45
+ const emit = defineEmits(['update:value', 'change']);
46
+
47
+ const checkboxGroup = inject('checkboxGroup', null);
48
+
49
+ const isChecked = computed(() => {
50
+ return checkboxGroup ? checkboxGroup.checkedValues.value.some((value: any) => deepEqual(value, props.item.value)) : props.value.some((v) => deepEqual(v, props.item.value));
51
+ });
52
+
53
+ const isDisabled = computed(() => {
54
+ return checkboxGroup ? checkboxGroup.disabled.value || props.disabled : props.disabled;
55
+ });
56
+
57
+ const isIndeterminate = ref(props.indeterminate);
58
+
59
+ const deepEqual = (x: any, y: any): boolean => {
60
+ if (x === y) return true;
61
+
62
+ if (typeof x === 'object' && x !== null && typeof y === 'object' && y !== null) {
63
+ if (Array.isArray(x)) {
64
+ if (!Array.isArray(y) || x.length !== y.length) return false;
65
+ return x.every((item, index) => deepEqual(item, y[index]));
66
+ }
67
+
68
+ const xKeys = Object.keys(x);
69
+ const yKeys = Object.keys(y);
70
+ if (xKeys.length !== yKeys.length) return false;
71
+
72
+ return xKeys.every((key) => {
73
+ return y.hasOwnProperty(key) && deepEqual(x[key], y[key]);
74
+ });
75
+ }
76
+
77
+ return false;
78
+ };
79
+
80
+ watch(
81
+ () => props.value,
82
+ (newVal) => {
83
+ isChecked.value = newVal.some((v) => deepEqual(v, props.item.value));
84
+ },
85
+ { deep: true }
86
+ );
87
+
88
+ watch(
89
+ () => props.indeterminate,
90
+ (newVal) => {
91
+ isIndeterminate.value = newVal;
92
+ }
93
+ );
94
+
95
+ const handleChange = () => {
96
+ if (isDisabled.value) return;
97
+
98
+ let newValues = [...(checkboxGroup ? checkboxGroup.checkedValues.value : props.value)];
99
+ const currentValue = props.item.value;
100
+
101
+ if (checkboxGroup && checkboxGroup.indeterminate) {
102
+ if (!isChecked.value && !isIndeterminate.value) {
103
+ newValues.push(currentValue);
104
+ } else if (isChecked.value && !isIndeterminate.value) {
105
+ newValues = newValues.filter((v) => !deepEqual(v, currentValue));
106
+ }
107
+ } else {
108
+ if (isChecked.value) {
109
+ newValues = newValues.filter((v) => !deepEqual(v, currentValue));
110
+ } else if (isIndeterminate.value) {
111
+ newValues.push(currentValue);
112
+ isIndeterminate.value = false;
113
+ } else {
114
+ isIndeterminate.value = true;
115
+ }
116
+ }
117
+
118
+ if (checkboxGroup) {
119
+ checkboxGroup.checkedValues.value = [...new Set(newValues)];
120
+ } else {
121
+ emit('update:value', [...new Set(newValues)]);
122
+ emit('change', [...new Set(newValues)]);
123
+ }
124
+ };
125
+ </script>
126
+
127
+ <style lang="scss" scoped>
128
+ .v-checkbox {
129
+ display: flex;
130
+ align-items: center;
131
+ cursor: pointer;
132
+ font-size: 14px;
133
+ color: #606266;
134
+ transition: all 0.3s;
135
+ margin-right: 16px;
136
+
137
+ &:last-child {
138
+ margin-right: 0;
139
+ }
140
+
141
+ &--disabled {
142
+ color: #c0c4cc;
143
+ cursor: not-allowed;
144
+
145
+ .v-checkbox-input {
146
+ background-color: #f5f7fa;
147
+ border-color: #e4e7ed;
148
+ cursor: not-allowed;
149
+ }
150
+ }
151
+
152
+ &--checked {
153
+ .v-checkbox-input {
154
+ border-color: #287afa !important;
155
+
156
+ .v-checkbox-inner {
157
+ background-color: #287afa !important;
158
+ display: block !important;
159
+ }
160
+ }
161
+ }
162
+
163
+ &--indeterminate {
164
+ .v-checkbox-input {
165
+ border-color: #287afa !important;
166
+ background-color: #f5f7fa !important;
167
+
168
+ &::after {
169
+ display: block;
170
+ }
171
+ }
172
+ }
173
+
174
+ .v-checkbox-input {
175
+ display: inline-block;
176
+ width: 16px;
177
+ height: 16px;
178
+ border: 1px solid #dcdfe6;
179
+ border-radius: 2px;
180
+ background-color: #fff;
181
+ position: relative;
182
+ margin-right: 8px;
183
+ cursor: pointer;
184
+ transition: all 0.3s;
185
+ vertical-align: middle;
186
+
187
+ .v-checkbox-inner {
188
+ display: none;
189
+ width: 12px;
190
+ height: 12px;
191
+ position: absolute;
192
+ left: 50%;
193
+ top: 50%;
194
+ transform: translate(-50%, -50%);
195
+ }
196
+
197
+ &::after {
198
+ content: '';
199
+ display: none;
200
+ position: absolute;
201
+ left: 5px;
202
+ top: 1px;
203
+ width: 6px;
204
+ height: 12px;
205
+ border: solid #287afa;
206
+ border-width: 0 2px 2px 0;
207
+ transform: rotate(45deg);
208
+ }
209
+ }
210
+
211
+ .v-checkbox-label {
212
+ display: inline-block;
213
+ }
214
+ }
215
+ </style>