hortimagic 1.0.0

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.
@@ -0,0 +1,177 @@
1
+ import { LitElement, css, html } from 'lit'
2
+ import { customElement, property } from 'lit/decorators.js'
3
+
4
+
5
+ /** 通知消息组件
6
+ * @example
7
+ * ```html
8
+ * <!-- 基础用法 -->
9
+ <hm-notification
10
+ title="提示"
11
+ content="这是一条通知信息">
12
+ </hm-notification>
13
+
14
+ <!-- 自定义颜色 -->
15
+ <hm-notification
16
+ title="成功"
17
+ content="操作成功"
18
+ text-color="#ffffff"
19
+ background-color="#4caf50">
20
+ </hm-notification>
21
+
22
+ <!-- 自定义显示时间(3秒) -->
23
+ <hm-notification
24
+ title="提示"
25
+ content="这条信息显示3秒"
26
+ display-time="3000">
27
+ </hm-notification>
28
+ ```
29
+ */
30
+ @customElement('hm-notification')
31
+ export class HmNotification extends LitElement {
32
+ /** 左边图标 */
33
+ @property()
34
+ leftIcon = 'magic-wand';
35
+
36
+ /** 标题 */
37
+ @property()
38
+ title = 'HortiMagic';
39
+
40
+ /** 正文 */
41
+ @property()
42
+ content = 'Hello iirose!';
43
+
44
+ /** 右边图标*/
45
+ @property()
46
+ rightIcon = '';
47
+
48
+ /** 显示时间,单位毫秒 */
49
+ @property()
50
+ displayTime = 999999;
51
+
52
+ // 自定义字体颜色属性
53
+ @property()
54
+ color = 'rgb(33,33,33)';
55
+
56
+ // 自定义背景颜色属性
57
+ @property()
58
+ backgroundColor = 'rgba(255,255,255,0.9)';
59
+
60
+ static styles = css`
61
+ :host{
62
+ display: block;
63
+ width: auto;
64
+ z-index: 9999999;
65
+ margin: 2px;
66
+ animation: slideInRight 0.3s ease-out forwards;
67
+ }
68
+
69
+ :host([leaving]) {
70
+ animation: slideOutRight 0.3s ease-in forwards;
71
+ }
72
+
73
+ @keyframes slideInRight {
74
+ from {
75
+ opacity: 0;
76
+ transform: translate3d(100%, 0, 0);
77
+ }
78
+
79
+ to {
80
+ opacity: 1;
81
+ transform: translate3d(0, 0, 0);
82
+ }
83
+ }
84
+
85
+ @keyframes slideOutRight {
86
+ from {
87
+ opacity: 1;
88
+ transform: translate3d(0, 0, 0);
89
+ }
90
+
91
+ to {
92
+ opacity: 0;
93
+ transform: translate3d(100%, 0, 0);
94
+ }
95
+ }
96
+
97
+ .hm-notification{
98
+ display: flex;
99
+ align-items: center;
100
+ width:fit-content;
101
+ max-width: 320px;
102
+ border-radius: 10px;
103
+
104
+ }
105
+ .hm-notification-main{
106
+ margin-right: 8px;
107
+ padding: 8px;
108
+ }
109
+ .hm-notification-title{
110
+ font-size: 16px;
111
+ font-weight: bold;
112
+ }
113
+ .hm-notification-content{
114
+ font-size: 14px;
115
+ }
116
+ .icondiv{
117
+ display: flex;
118
+ align-items: center;
119
+ justify-content: center;
120
+ width: 44px;
121
+ height: 44px;
122
+ }
123
+ `;
124
+
125
+ // 组件挂载后启动定时器
126
+ firstUpdated() {
127
+ if (this.displayTime > 0) {
128
+ setTimeout(() => {
129
+ this.startLeaveAnimation();
130
+ }, this.displayTime);
131
+ }
132
+ }
133
+
134
+ private startLeaveAnimation() {
135
+ this.setAttribute('leaving', '');
136
+
137
+ // 动画结束后移除元素
138
+ setTimeout(() => {
139
+ this.remove();
140
+ }, 300); // 与动画时长保持一致
141
+ }
142
+
143
+ render() {
144
+ return html`
145
+ <div
146
+ class="hm-notification"
147
+ style="${this.color ? `border-color: ${this.color};` : ''}
148
+ ${this.color ? `color: ${this.color};` : ''}
149
+ ${this.backgroundColor ? `background-color: ${this.backgroundColor};` : ''}"
150
+ >
151
+ ${this.leftIcon ? html`
152
+ <div class="icondiv">
153
+ <hm-icon icon="${this.leftIcon}" size="24px"></hm-icon>
154
+ </div>
155
+ ` : ''}
156
+
157
+ <div class="hm-notification-main">
158
+ <div class="hm-notification-title">${this.title}</div>
159
+ <div class="hm-notification-content">${this.content}</div>
160
+ </div>
161
+ ${this.rightIcon ? html`
162
+ <div class="icondiv">
163
+ <hm-icon icon="${this.rightIcon}" size="24px"></hm-icon>
164
+ </div>
165
+ ` : ''}
166
+ </div>
167
+ `;
168
+ }
169
+
170
+
171
+ }
172
+
173
+ declare global {
174
+ interface HTMLElementTagNameMap {
175
+ "hm-notification": HmNotification;
176
+ }
177
+ }
@@ -0,0 +1,378 @@
1
+ import { LitElement, css, html } from 'lit'
2
+ import { customElement, property, query } from 'lit/decorators.js'
3
+
4
+ /**
5
+ * 滑动单元格组件
6
+ * 实现左右滑动显示操作按钮的交互效果
7
+ *
8
+ * @slot content - 主内容区域
9
+ * @slot left-actions - 左侧操作按钮组
10
+ * @slot right-actions - 右侧操作按钮组
11
+ *
12
+ * @example
13
+ * <hm-swipe-cell>
14
+ * <!-- 主内容 -->
15
+ * <div slot="content">...</div>
16
+ * <!-- 左侧操作按钮 -->
17
+ * <div slot="left-actions">...</div>
18
+ * <!-- 右侧操作按钮 -->
19
+ * <div slot="right-actions">...</div>
20
+ * </hm-swipe-cell>
21
+ */
22
+ @customElement('hm-swipe-cell')
23
+ export class HmSwipeCell extends LitElement {
24
+ @property() _isDragging = false;
25
+ @property() _startX = 0;
26
+ @property() _currentTranslate = 0;
27
+ @property() _prevTranslate = 0;
28
+ @property() _animationId = 0;
29
+ @property() _velocity = 0;
30
+ @property() _lastX = 0;
31
+ @property() _lastTime = 0;
32
+ @property() _isOpen = false;
33
+ @property() rightButtonName = '右侧按钮';
34
+ /**
35
+ * 右边按钮点击回调函数
36
+ */
37
+ @property()
38
+ rightButtonCallback = function () {
39
+ console.debug('点击了一下');
40
+ };
41
+
42
+ @query('.slider') sliderElement!: HTMLElement;
43
+ @query('.content') contentElement!: HTMLElement;
44
+ @query('.left-actions') leftActions!: HTMLElement;
45
+ @query('.right-actions') rightActions!: HTMLElement;
46
+
47
+ leftActionsWidth: number = 0;
48
+ rightActionsWidth: number = 0;
49
+
50
+ static styles = css`
51
+ :host {
52
+ display: block;
53
+ overflow: hidden;
54
+ position: relative;
55
+ user-select: none;
56
+ touch-action: pan-y;
57
+ height: 60px;
58
+ background: #f9f9f9;
59
+ border-radius: 8px;
60
+ margin: 10px 0;
61
+ }
62
+ .swipe-container {
63
+ position: relative;
64
+ width: 100%;
65
+ height: 100%;
66
+ background: white;
67
+ border-radius: 8px;
68
+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
69
+ overflow: hidden;
70
+ }
71
+
72
+ .slider {
73
+ position: relative;
74
+ width: 100%;
75
+ height: 100%;
76
+ transition: transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
77
+ will-change: transform;
78
+ z-index: 2;
79
+ background: white;
80
+ }
81
+
82
+ .content {
83
+ display: flex;
84
+ align-items: center;
85
+ justify-content: space-between;
86
+ padding: 0 15px;
87
+ height: 100%;
88
+ width: 100%;
89
+ position: relative; // 改为相对定位
90
+ top: 0;
91
+ left: 0;
92
+ background: white;
93
+ box-sizing: border-box;
94
+ border-radius: 8px;
95
+ }
96
+
97
+ .actions {
98
+ position: absolute;
99
+ top: 0;
100
+ bottom: 0;
101
+ display: flex;
102
+ align-items: center;
103
+ z-index: 1;
104
+ transition: transform 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94);
105
+ }
106
+
107
+ .left-actions {
108
+ left: 0;
109
+ padding-left: 10px;
110
+ transform: translateX(-100%);
111
+ }
112
+
113
+ .right-actions {
114
+ right: 0;
115
+ padding-right: 10px;
116
+ transform: translateX(100%);
117
+ }
118
+
119
+ .action-btn {
120
+ height: 44px;
121
+ border: none;
122
+ color: white;
123
+ padding: 0 20px;
124
+ cursor: pointer;
125
+ font-size: 14px;
126
+ display: flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ transition: all 0.2s ease;
130
+ border-radius: 6px;
131
+ margin: 0 4px;
132
+ min-width: 80px;
133
+ font-weight: 500;
134
+ }
135
+
136
+ .action-btn:hover {
137
+ transform: scale(1.05);
138
+ filter: brightness(1.1);
139
+ }
140
+
141
+ .action-btn:active {
142
+ transform: scale(0.95);
143
+ }
144
+
145
+ .action-btn.favorite {
146
+ background: linear-gradient(135deg, #2196F3, #1976D2);
147
+ }
148
+
149
+ .action-btn.delete {
150
+ background: linear-gradient(135deg, #f44336, #d32f2f);
151
+ }
152
+
153
+ .action-btn.mark {
154
+ background: linear-gradient(135deg, #FF9800, #F57C00);
155
+ }
156
+
157
+ .action-btn.archive {
158
+ background: linear-gradient(135deg, #9C27B0, #7B1FA2);
159
+ }
160
+
161
+ .action-btn.share {
162
+ background: linear-gradient(135deg, #4CAF50, #388E3C);
163
+ }
164
+
165
+ .action-btn.edit {
166
+ background: linear-gradient(135deg, #607D8B, #455A64);
167
+ }
168
+ .contentslot{
169
+ width: 100%;
170
+ }
171
+ `;
172
+ firstUpdated() {
173
+ this.calculateActionWidths();
174
+ this.addEventListeners();
175
+ }
176
+
177
+ disconnectedCallback() {
178
+ super.disconnectedCallback();
179
+ this.removeEventListeners();
180
+ }
181
+
182
+ calculateActionWidths() {
183
+ this.leftActionsWidth = this.leftActions ? this.leftActions.offsetWidth : 0;
184
+ this.rightActionsWidth = this.rightActions ? this.rightActions.offsetWidth : 0;
185
+ }
186
+
187
+ addEventListeners() {
188
+ this.sliderElement.addEventListener('mousedown', this.onDragStart);
189
+ this.sliderElement.addEventListener('touchstart', this.onTouchStart, { passive: false });
190
+
191
+ document.addEventListener('mousemove', this.onDragMove);
192
+ document.addEventListener('touchmove', this.onTouchMove, { passive: false });
193
+
194
+ document.addEventListener('mouseup', this.onDragEnd);
195
+ document.addEventListener('touchend', this.onTouchEnd);
196
+ }
197
+
198
+ removeEventListeners() {
199
+ this.sliderElement.removeEventListener('mousedown', this.onDragStart);
200
+ this.sliderElement.removeEventListener('touchstart', this.onTouchStart);
201
+
202
+ document.removeEventListener('mousemove', this.onDragMove);
203
+ document.removeEventListener('touchmove', this.onTouchMove);
204
+
205
+ document.removeEventListener('mouseup', this.onDragEnd);
206
+ document.removeEventListener('touchend', this.onTouchEnd);
207
+ }
208
+
209
+ onDragStart = (e: MouseEvent) => {
210
+ e.preventDefault();
211
+ this.startDrag(e.clientX);
212
+ this.sliderElement.style.cursor = 'grabbing';
213
+ this.sliderElement.style.transition = 'none';
214
+ }
215
+
216
+ onTouchStart = (e: TouchEvent) => {
217
+ e.preventDefault();
218
+ this.startDrag(e.touches[0].clientX);
219
+ this.sliderElement.style.transition = 'none';
220
+ }
221
+
222
+ startDrag = (clientX: number) => {
223
+ this._isDragging = true;
224
+ this._startX = clientX;
225
+ this._lastX = clientX;
226
+ this._lastTime = Date.now();
227
+ this._isOpen = Math.abs(this._prevTranslate) > 10;
228
+ // 每次拖动开始时重新计算按钮宽度
229
+ this.calculateActionWidths();
230
+ }
231
+
232
+ onDragMove = (e: MouseEvent) => {
233
+ if (!this._isDragging) return;
234
+ e.preventDefault();
235
+ this.handleMove(e.clientX);
236
+ }
237
+
238
+ onTouchMove = (e: TouchEvent) => {
239
+ if (!this._isDragging) return;
240
+ e.preventDefault();
241
+ this.handleMove(e.touches[0].clientX);
242
+ }
243
+
244
+ handleMove(currentX: number) {
245
+ const currentTime = Date.now();
246
+ const timeDiff = currentTime - this._lastTime;
247
+
248
+ if (timeDiff > 0) {
249
+ this._velocity = (currentX - this._lastX) / timeDiff;
250
+ this._lastX = currentX;
251
+ this._lastTime = currentTime;
252
+ }
253
+
254
+ const diff = currentX - this._startX;
255
+ let newTranslate = this._prevTranslate + diff;
256
+
257
+ // 限制滑动范围,确保按钮紧贴内容边界
258
+ if (newTranslate > this.leftActionsWidth) {
259
+ // 添加弹性效果,超过边界时增加阻力
260
+ const overshoot = newTranslate - this.leftActionsWidth;
261
+ newTranslate = this.leftActionsWidth + this.easeOut(overshoot, 30);
262
+ } else if (newTranslate < -this.rightActionsWidth) {
263
+ const overshoot = newTranslate + this.rightActionsWidth;
264
+ newTranslate = -this.rightActionsWidth + this.easeOut(overshoot, 30);
265
+ }
266
+
267
+ this._currentTranslate = newTranslate;
268
+ this.updateSliderPosition();
269
+ }
270
+
271
+ // 弹性效果函数,使超出边界时有缓冲效果
272
+ easeOut(overshoot: number, maxResistance: number): number {
273
+ maxResistance;
274
+ return overshoot * 0.2;
275
+ }
276
+
277
+ onDragEnd = () => {
278
+ this.finishDrag();
279
+ this.sliderElement.style.cursor = 'grab';
280
+ }
281
+
282
+ onTouchEnd = () => {
283
+ this.finishDrag();
284
+ }
285
+
286
+ finishDrag() {
287
+ this._isDragging = false;
288
+ this.sliderElement.style.transition = 'transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94)';
289
+
290
+ // 降低阈值,使按钮更容易跟随显示
291
+ const threshold = 5; // 进一步降低阈值,提高灵敏度
292
+ const velocityThreshold = 0.1; // 降低速度阈值
293
+
294
+ let targetTranslate = 0;
295
+
296
+ // 优化判断逻辑,优先考虑滑动距离
297
+ if (this._currentTranslate > threshold ||
298
+ (this._currentTranslate > 0 && this._velocity > velocityThreshold)) {
299
+ // 显示左侧按钮,确保完全展开
300
+ targetTranslate = this.leftActionsWidth;
301
+ } else if (this._currentTranslate < -threshold ||
302
+ (this._currentTranslate < 0 && this._velocity < -velocityThreshold)) {
303
+ // 显示右侧按钮,确保完全展开
304
+ targetTranslate = -this.rightActionsWidth;
305
+ } else {
306
+ // 未达阈值,恢复原位
307
+ targetTranslate = 0;
308
+ }
309
+
310
+ // 优化已打开状态的处理逻辑
311
+ if (this._isOpen) {
312
+ // 降低关闭阈值,使关闭操作更灵敏
313
+ const closeThreshold = 5; // 进一步降低关闭阈值
314
+ if ((this._prevTranslate > 0 && this._currentTranslate < this._prevTranslate - closeThreshold) ||
315
+ (this._prevTranslate < 0 && this._currentTranslate > this._prevTranslate + closeThreshold)) {
316
+ targetTranslate = 0;
317
+ } else {
318
+ // 保持当前打开状态
319
+ targetTranslate = this._prevTranslate;
320
+ }
321
+ }
322
+
323
+ this._currentTranslate = targetTranslate;
324
+ this._prevTranslate = targetTranslate;
325
+
326
+ this.updateSliderPosition();
327
+ this._velocity = 0;
328
+ }
329
+
330
+ updateSliderPosition() {
331
+ if (this._animationId) {
332
+ cancelAnimationFrame(this._animationId);
333
+ }
334
+
335
+ this._animationId = requestAnimationFrame(() => {
336
+ this.sliderElement.style.transform = `translateX(${this._currentTranslate}px)`;
337
+
338
+ // 优化按钮跟随逻辑,确保按钮始终紧贴内容边界
339
+ if (this._currentTranslate > 0) {
340
+ // 向右滑动时,左侧按钮从左侧平滑跟随
341
+ const leftProgress = Math.min(this._currentTranslate / this.leftActionsWidth, 1);
342
+ this.leftActions.style.transform = `translateX(${-100 + (leftProgress * 100)}%)`;
343
+ this.rightActions.style.transform = 'translateX(100%)';
344
+ } else if (this._currentTranslate < 0) {
345
+ // 向左滑动时,右侧按钮从右侧平滑跟随
346
+ const rightProgress = Math.min(-this._currentTranslate / this.rightActionsWidth, 1);
347
+ this.rightActions.style.transform = `translateX(${100 - (rightProgress * 100)}%)`;
348
+ this.leftActions.style.transform = 'translateX(-100%)';
349
+ } else {
350
+ // 居中时隐藏所有按钮
351
+ this.leftActions.style.transform = 'translateX(-100%)';
352
+ this.rightActions.style.transform = 'translateX(100%)';
353
+ }
354
+ });
355
+ }
356
+
357
+ render() {
358
+ return html`
359
+ <div class="swipe-container">
360
+ <div class="actions left-actions">
361
+ <slot name="left-actions"> </slot>
362
+ </div>
363
+ <div class="slider">
364
+ <slot name="content" class="content">
365
+ <hm-cell></hm-cell>
366
+ </slot>
367
+ </div>
368
+ <div class="actions right-actions">
369
+ <slot name="right-actions">
370
+ <hm-button type="primary" @hm-button-click="${this.rightButtonCallback}"
371
+ >${this.rightButtonName}</hm-button
372
+ >
373
+ </slot>
374
+ </div>
375
+ </div>
376
+ `;
377
+ }
378
+ }
@@ -0,0 +1,167 @@
1
+ import { LitElement, html, css } from 'lit';
2
+ import { customElement, property } from 'lit/decorators.js';
3
+
4
+ /**
5
+ * 滑动开关组件
6
+ *
7
+ * @example
8
+ * ```html
9
+ * <!-- 基础用法 -->
10
+ * <hm-switch></hm-switch>
11
+ *
12
+ * <!-- 默认开启 -->
13
+ * <hm-switch checked></hm-switch>
14
+ *
15
+ * <!-- 禁用状态 -->
16
+ * <hm-switch disabled></hm-switch>
17
+ *
18
+ * <!-- 加载状态 -->
19
+ * <hm-switch loading></hm-switch>
20
+ *
21
+ * <!-- 自定义颜色 -->
22
+ * <hm-switch color="#ff4757"></hm-switch>
23
+ *
24
+ * <!-- 带图标 -->
25
+ * <hm-switch openIcon="check" closeIcon="close"></hm-switch>
26
+ *
27
+ * <!-- 监听状态变化 -->
28
+ * <hm-switch @hm-switch-change="${(e) => console.log('开关状态:', e.detail.checked)}"></hm-switch>
29
+ * ```
30
+ */
31
+ @customElement('hm-switch')
32
+ export class HmSwitch extends LitElement {
33
+ /** 开关状态 */
34
+ @property({ type: Boolean }) checked = false;
35
+ /** 是否禁用 */
36
+ @property({ type: Boolean }) disabled = false;
37
+ /** 加载状态 */
38
+ @property({ type: Boolean }) loading = false;
39
+
40
+ /** 开关打开时的颜色 */
41
+ @property({ type: String }) color = '#1890ff';
42
+
43
+ /** 自定义开启状态内容 */
44
+ @property({ type: String }) openContent = '';
45
+
46
+ /** 自定义关闭状态内容 */
47
+ @property({ type: String }) closeContent = '';
48
+ /** 自定义开启状态图标 */
49
+ @property({ type: String }) openIcon = '';
50
+
51
+ /** 自定义关闭状态图标 */
52
+ @property({ type: String }) closeIcon = '';
53
+
54
+ change() {
55
+ if (this.disabled || this.loading) return;
56
+ this.checked = !this.checked;
57
+ // console.debug('changed!!');
58
+ // 触发自定义事件供外部监听
59
+ this.dispatchEvent(new CustomEvent('hm-switch-change', {
60
+ detail: { checked: this.checked },
61
+ bubbles: true,
62
+ composed: true
63
+ }));
64
+ }
65
+
66
+ render() {
67
+ return html`
68
+ <div
69
+ class="switch ${this.disabled ? 'disabled' : ''} ${this.loading ? 'loading' : ''} ${this.checked ? 'checked' : ''}"
70
+ @click="${this.change}"
71
+ @touchstart="${this.change}"
72
+ style="--switch-color: ${this.color}"
73
+ >
74
+ <div class="switch-inner">
75
+ ${this.checked ?
76
+ (this.openIcon ? html`<hm-icon icon="${this.openIcon}" size="14px"></hm-icon>` :
77
+ this.openContent ? html`<span>${this.openContent}</span>` : '') :
78
+ (this.closeIcon ? html`<hm-icon icon="${this.closeIcon}" size="14px"></hm-icon>` :
79
+ this.closeContent ? html`<span>${this.closeContent}</span>` : '')}
80
+ </div>
81
+ </div>
82
+ `;
83
+ }
84
+
85
+ static styles = css`
86
+ .switch {
87
+ position: relative;
88
+ display: inline-block;
89
+ width: 44px;
90
+ height: 22px;
91
+ vertical-align: middle;
92
+ border: 1px solid #ccc;
93
+ border-radius: 20px;
94
+ background-color: #ccc;
95
+ cursor: pointer;
96
+ transition: all 0.3s;
97
+ user-select: none;
98
+ }
99
+
100
+ .switch.checked {
101
+ background-color: var(--switch-color, #1890ff);
102
+ border-color: var(--switch-color, #1890ff);
103
+ }
104
+
105
+ .switch.disabled {
106
+ cursor: not-allowed;
107
+ opacity: 0.6;
108
+ }
109
+
110
+ .switch.loading {
111
+ cursor: wait;
112
+ opacity: 0.6;
113
+ }
114
+
115
+ .switch-inner {
116
+ position: absolute;
117
+ top: 2px;
118
+ left: 2px;
119
+ width: 18px;
120
+ height: 18px;
121
+ background-color: #fff;
122
+ border-radius: 50%;
123
+ transition: all 0.3s;
124
+ display: flex;
125
+ align-items: center;
126
+ justify-content: center;
127
+ font-size: 12px;
128
+ }
129
+
130
+ .switch.checked .switch-inner {
131
+ left: calc(100% - 20px);
132
+ }
133
+
134
+ .switch.loading::after {
135
+ content: '';
136
+ position: absolute;
137
+ top: 50%;
138
+ left: 50%;
139
+ width: 12px;
140
+ height: 12px;
141
+ margin-top: -6px;
142
+ margin-left: -6px;
143
+ border: 2px solid transparent;
144
+ border-top-color: currentColor;
145
+ border-radius: 50%;
146
+ animation: rotate 1s linear infinite;
147
+ }
148
+
149
+ @keyframes rotate {
150
+ from {
151
+ transform: rotate(0deg);
152
+ }
153
+ to {
154
+ transform: rotate(360deg);
155
+ }
156
+ }
157
+
158
+ hm-icon {
159
+ font-size: 12px;
160
+ width: 12px;
161
+ height: 12px;
162
+ display: flex;
163
+ align-items: center;
164
+ justify-content: center;
165
+ }
166
+ `;
167
+ }