km-card-layout-component-miniprogram 0.1.41 → 0.1.42
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.
- package/miniprogram_dist/components/card-layout/elements/icon-element/index.js +2 -2
- package/miniprogram_dist/components/card-layout/elements/icon-element/index.wxml +1 -1
- package/miniprogram_dist/components/card-layout/elements/icon-font.wxss +8 -4
- package/miniprogram_dist/components/card-layout/icon-map.js +1 -0
- package/miniprogram_dist/components/card-layout/index.js +142 -16
- package/miniprogram_dist/components/card-layout/index.wxml +46 -22
- package/miniprogram_dist/components/card-layout/index.wxss +82 -0
- package/package.json +1 -1
- package/src/components/card-layout/elements/icon-element/index.ts +2 -2
- package/src/components/card-layout/elements/icon-element/index.wxml +1 -1
- package/src/components/card-layout/elements/icon-font.wxss +8 -4
- package/src/components/card-layout/icon-map.ts +1 -0
- package/src/components/card-layout/index.ts +160 -18
- package/src/components/card-layout/index.wxml +46 -22
- package/src/components/card-layout/index.wxss +82 -0
|
@@ -5,13 +5,13 @@ const icon_map_1 = require("../../icon-map");
|
|
|
5
5
|
const normalizeIconName = (name) => {
|
|
6
6
|
if (!name)
|
|
7
7
|
return "";
|
|
8
|
-
return name.startsWith("icon-") ? name.slice(5) : name;
|
|
8
|
+
return name.startsWith("layout-icon-") ? name.slice(5) : name;
|
|
9
9
|
};
|
|
10
10
|
const buildIconClassName = (name) => {
|
|
11
11
|
const normalized = normalizeIconName(name);
|
|
12
12
|
if (!normalized)
|
|
13
13
|
return "";
|
|
14
|
-
return `icon-${normalized}`;
|
|
14
|
+
return `layout-icon-${normalized}`;
|
|
15
15
|
};
|
|
16
16
|
const buildIconCode = (name) => {
|
|
17
17
|
const normalized = normalizeIconName(name);
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<view class="km-node km-node--icon canvas-item" style="{{wrapperStyle}}">
|
|
2
|
-
<view class="km-node__icon
|
|
2
|
+
<view class="km-node__icon layoutIconFont {{iconClass}} canvas-item" style="{{contentStyle}}" data-icon="{{iconCode}}"></view>
|
|
3
3
|
</view>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
@font-face {
|
|
2
2
|
font-family: "layoutIconFont"; /* Project id 5095635 */
|
|
3
|
-
src: url('//at.alicdn.com/t/c/
|
|
4
|
-
url('//at.alicdn.com/t/c/
|
|
5
|
-
url('//at.alicdn.com/t/c/
|
|
6
|
-
url('//at.alicdn.com/t/c/
|
|
3
|
+
src: url('//at.alicdn.com/t/c/font_5095635_0u3b33ft9ub.woff2?t=1770624313420') format('woff2'),
|
|
4
|
+
url('//at.alicdn.com/t/c/font_5095635_0u3b33ft9ub.woff?t=1770624313420') format('woff'),
|
|
5
|
+
url('//at.alicdn.com/t/c/font_5095635_0u3b33ft9ub.ttf?t=1770624313420') format('truetype'),
|
|
6
|
+
url('//at.alicdn.com/t/c/font_5095635_0u3b33ft9ub.svg?t=1770624313420#layoutIconFont') format('svg');
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
.layoutIconFont {
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
-moz-osx-font-smoothing: grayscale;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
.layout-icon-refresh:before {
|
|
18
|
+
content: "\e62b";
|
|
19
|
+
}
|
|
20
|
+
|
|
17
21
|
.layout-icon-round:before {
|
|
18
22
|
content: "\e608";
|
|
19
23
|
}
|
|
@@ -7,17 +7,18 @@ const EMPTY_COMPANY_DUTY = {
|
|
|
7
7
|
company: "",
|
|
8
8
|
duty: "",
|
|
9
9
|
};
|
|
10
|
+
const SWITCH_ANIMATION_MS = 420;
|
|
11
|
+
const SWIPE_MIN_DISTANCE = 40;
|
|
12
|
+
const SWIPE_DIRECTION_RATIO = 1.2;
|
|
10
13
|
/**
|
|
11
|
-
*
|
|
14
|
+
* 规范�?moreCardInfo.company,保证长度始终为 2
|
|
12
15
|
*/
|
|
13
16
|
function normalizeMoreCompany(data) {
|
|
14
17
|
var _a, _b;
|
|
15
18
|
const origin = (_b = (_a = data.user) === null || _a === void 0 ? void 0 : _a.moreCardInfo) === null || _b === void 0 ? void 0 : _b.company;
|
|
16
|
-
// 不存在 / 不是数组 → 不处理
|
|
17
19
|
if (!Array.isArray(origin)) {
|
|
18
20
|
return data;
|
|
19
21
|
}
|
|
20
|
-
// 长度 === 0 → 不处理
|
|
21
22
|
if (origin.length === 0) {
|
|
22
23
|
return data;
|
|
23
24
|
}
|
|
@@ -43,13 +44,22 @@ const pickCardId = (layout, idx) => {
|
|
|
43
44
|
return `card-${idx}`;
|
|
44
45
|
};
|
|
45
46
|
const buildCards = (layouts) => {
|
|
46
|
-
return layouts.map((layout, idx) =>
|
|
47
|
-
|
|
48
|
-
cardStyle
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
return layouts.map((layout, idx) => {
|
|
48
|
+
const baseCardStyle = (0, index_1.buildCardStyle)(layout, "rpx");
|
|
49
|
+
const cardStyle = (0, index_1.styleObjectToString)(baseCardStyle, "rpx");
|
|
50
|
+
const sizeStyle = (0, index_1.styleObjectToString)({
|
|
51
|
+
width: baseCardStyle.width,
|
|
52
|
+
height: baseCardStyle.height,
|
|
53
|
+
}, "rpx");
|
|
54
|
+
return {
|
|
55
|
+
id: pickCardId(layouts[idx], idx),
|
|
56
|
+
cardStyle,
|
|
57
|
+
sizeStyle,
|
|
58
|
+
backgroundImage: layout.backgroundImage || "",
|
|
59
|
+
backgroundStyle: (0, index_1.styleObjectToString)((0, index_1.buildBackgroundStyle)(layout, "rpx"), "rpx"),
|
|
60
|
+
elements: layout.children || [],
|
|
61
|
+
};
|
|
62
|
+
});
|
|
53
63
|
};
|
|
54
64
|
const nextTick = () => new Promise((resolve) => {
|
|
55
65
|
wx.nextTick(() => resolve());
|
|
@@ -76,6 +86,20 @@ Component({
|
|
|
76
86
|
rootData: {},
|
|
77
87
|
firstCard: [],
|
|
78
88
|
shareImage: "",
|
|
89
|
+
activeCard: null,
|
|
90
|
+
canvasCard: null,
|
|
91
|
+
frontCard: null,
|
|
92
|
+
backCard: null,
|
|
93
|
+
activeIndex: 0,
|
|
94
|
+
flipEnabled: false,
|
|
95
|
+
showToggle: false,
|
|
96
|
+
isFlipped: false,
|
|
97
|
+
isSwitching: false,
|
|
98
|
+
switch: {
|
|
99
|
+
name: "refresh",
|
|
100
|
+
size: 14,
|
|
101
|
+
style: "fill",
|
|
102
|
+
},
|
|
79
103
|
},
|
|
80
104
|
observers: {
|
|
81
105
|
layout() {
|
|
@@ -100,18 +124,112 @@ Component({
|
|
|
100
124
|
return self._fontReady;
|
|
101
125
|
},
|
|
102
126
|
rebuild() {
|
|
127
|
+
const self = this;
|
|
128
|
+
if (self._switchTimer) {
|
|
129
|
+
clearTimeout(self._switchTimer);
|
|
130
|
+
self._switchTimer = null;
|
|
131
|
+
}
|
|
103
132
|
const data = normalizeMoreCompany(this.data.data);
|
|
104
133
|
const layoutInput = (0, helpers_1.hasCompanyDutyKey)(this.data.layout)
|
|
105
134
|
? (0, index_1.processCardLayout)(this.data.layout, data)
|
|
106
135
|
: this.data.layout;
|
|
107
136
|
const rootData = (0, index_1.handleSpecialFields)(data);
|
|
108
137
|
if (!layoutInput.length) {
|
|
109
|
-
this.setData({
|
|
138
|
+
this.setData({
|
|
139
|
+
cards: [],
|
|
140
|
+
rootData,
|
|
141
|
+
activeCard: null,
|
|
142
|
+
canvasCard: null,
|
|
143
|
+
frontCard: null,
|
|
144
|
+
backCard: null,
|
|
145
|
+
activeIndex: 0,
|
|
146
|
+
flipEnabled: false,
|
|
147
|
+
showToggle: false,
|
|
148
|
+
isFlipped: false,
|
|
149
|
+
isSwitching: false,
|
|
150
|
+
});
|
|
110
151
|
return;
|
|
111
152
|
}
|
|
112
153
|
const normalizedLayouts = (0, index_1.normalizeLayout)(layoutInput);
|
|
113
154
|
const cards = buildCards(normalizedLayouts);
|
|
114
|
-
|
|
155
|
+
const activeIndex = 0;
|
|
156
|
+
const flipEnabled = cards.length > 1;
|
|
157
|
+
const activeCard = cards[activeIndex] || null;
|
|
158
|
+
const frontCard = cards[0] || null;
|
|
159
|
+
const backCard = cards[1] || null;
|
|
160
|
+
this.setData({
|
|
161
|
+
cards,
|
|
162
|
+
rootData,
|
|
163
|
+
firstCard: [cards[0]],
|
|
164
|
+
activeIndex,
|
|
165
|
+
activeCard,
|
|
166
|
+
canvasCard: activeCard,
|
|
167
|
+
frontCard,
|
|
168
|
+
backCard,
|
|
169
|
+
flipEnabled,
|
|
170
|
+
showToggle: flipEnabled,
|
|
171
|
+
isFlipped: false,
|
|
172
|
+
isSwitching: false,
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
handleToggleCard() {
|
|
176
|
+
const cards = this.data.cards;
|
|
177
|
+
if (!cards || cards.length < 2)
|
|
178
|
+
return;
|
|
179
|
+
if (this.data.isSwitching)
|
|
180
|
+
return;
|
|
181
|
+
const self = this;
|
|
182
|
+
if (self._switchTimer) {
|
|
183
|
+
clearTimeout(self._switchTimer);
|
|
184
|
+
self._switchTimer = null;
|
|
185
|
+
}
|
|
186
|
+
const nextIndex = this.data.activeIndex === 0 ? 1 : 0;
|
|
187
|
+
this.setData({
|
|
188
|
+
activeIndex: nextIndex,
|
|
189
|
+
activeCard: cards[nextIndex],
|
|
190
|
+
canvasCard: cards[nextIndex],
|
|
191
|
+
isFlipped: nextIndex === 1,
|
|
192
|
+
isSwitching: true,
|
|
193
|
+
});
|
|
194
|
+
self._switchTimer = setTimeout(() => {
|
|
195
|
+
self._switchTimer = null;
|
|
196
|
+
this.setData({ isSwitching: false });
|
|
197
|
+
}, SWITCH_ANIMATION_MS);
|
|
198
|
+
},
|
|
199
|
+
onToggleTap() {
|
|
200
|
+
this.handleToggleCard();
|
|
201
|
+
},
|
|
202
|
+
onTouchStart(event) {
|
|
203
|
+
const touch = event.touches && event.touches[0];
|
|
204
|
+
if (!touch)
|
|
205
|
+
return;
|
|
206
|
+
const self = this;
|
|
207
|
+
self._touchStartX = touch.clientX;
|
|
208
|
+
self._touchStartY = touch.clientY;
|
|
209
|
+
},
|
|
210
|
+
onTouchEnd(event) {
|
|
211
|
+
const self = this;
|
|
212
|
+
const touch = event.changedTouches && event.changedTouches[0];
|
|
213
|
+
if (!touch)
|
|
214
|
+
return;
|
|
215
|
+
const startX = self._touchStartX;
|
|
216
|
+
const startY = self._touchStartY;
|
|
217
|
+
self._touchStartX = null;
|
|
218
|
+
self._touchStartY = null;
|
|
219
|
+
if (typeof startX !== "number" || typeof startY !== "number")
|
|
220
|
+
return;
|
|
221
|
+
const dx = touch.clientX - startX;
|
|
222
|
+
const dy = touch.clientY - startY;
|
|
223
|
+
const absDx = Math.abs(dx);
|
|
224
|
+
const absDy = Math.abs(dy);
|
|
225
|
+
if (absDx > SWIPE_MIN_DISTANCE && absDx > absDy * SWIPE_DIRECTION_RATIO) {
|
|
226
|
+
this.handleToggleCard();
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
onTouchCancel() {
|
|
230
|
+
const self = this;
|
|
231
|
+
self._touchStartX = null;
|
|
232
|
+
self._touchStartY = null;
|
|
115
233
|
},
|
|
116
234
|
async handleDrawCanvas(options) {
|
|
117
235
|
const self = this;
|
|
@@ -138,16 +256,22 @@ Component({
|
|
|
138
256
|
self._isDrawing = false;
|
|
139
257
|
}
|
|
140
258
|
}
|
|
141
|
-
},
|
|
142
|
-
async handleDrawShareCanvas() {
|
|
259
|
+
}, async handleDrawShareCanvas() {
|
|
143
260
|
var _a, _b, _c;
|
|
144
261
|
const self = this;
|
|
145
262
|
if (self._isDrawing)
|
|
146
263
|
return;
|
|
147
264
|
self._isDrawing = true;
|
|
265
|
+
let previousCanvasCard;
|
|
148
266
|
try {
|
|
149
267
|
// wait for setData / component render
|
|
150
268
|
await nextTick();
|
|
269
|
+
const frontCard = this.data.frontCard || this.data.activeCard;
|
|
270
|
+
previousCanvasCard = this.data.canvasCard;
|
|
271
|
+
if (frontCard && frontCard !== previousCanvasCard) {
|
|
272
|
+
await new Promise((resolve) => this.setData({ canvasCard: frontCard }, resolve));
|
|
273
|
+
await nextTick();
|
|
274
|
+
}
|
|
151
275
|
const layoutPath = await this.handleDrawCanvas({ waitForReady: false, skipDrawingGuard: true });
|
|
152
276
|
if (!layoutPath)
|
|
153
277
|
return;
|
|
@@ -165,6 +289,9 @@ Component({
|
|
|
165
289
|
return filePath;
|
|
166
290
|
}
|
|
167
291
|
finally {
|
|
292
|
+
if (previousCanvasCard && previousCanvasCard !== this.data.canvasCard) {
|
|
293
|
+
this.setData({ canvasCard: previousCanvasCard });
|
|
294
|
+
}
|
|
168
295
|
self._isDrawing = false;
|
|
169
296
|
}
|
|
170
297
|
},
|
|
@@ -173,8 +300,7 @@ Component({
|
|
|
173
300
|
global: true,
|
|
174
301
|
family: "layoutIconFont",
|
|
175
302
|
scopes: ["native"],
|
|
176
|
-
|
|
177
|
-
source: "https://at.alicdn.com/t/c/font_5095635_ztv7ro0zm59.ttf?t=1766563440291",
|
|
303
|
+
source: "https://at.alicdn.com/t/c/font_5095635_0u3b33ft9ub.ttf?t=1770624313420",
|
|
178
304
|
});
|
|
179
305
|
},
|
|
180
306
|
},
|
|
@@ -1,39 +1,63 @@
|
|
|
1
|
-
<
|
|
2
|
-
<
|
|
3
|
-
<view class="km-card-
|
|
4
|
-
<view class="km-card-
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
</block>
|
|
10
|
-
</view>
|
|
1
|
+
<view class="km-card-layout layout-view-container" bindtouchstart="onTouchStart" bindtouchend="onTouchEnd" bindtouchcancel="onTouchCancel">
|
|
2
|
+
<view class="km-card-layout__item canvas-item">
|
|
3
|
+
<view wx:if="{{flipEnabled}}" class="km-card-layout__flip {{isFlipped ? 'is-flipped' : ''}} {{isSwitching ? 'is-switching' : ''}}" style="{{frontCard.sizeStyle}}">
|
|
4
|
+
<view class="km-card-layout__face km-card-layout__face--front">
|
|
5
|
+
<template is="card-content" data="{{ idPrefix: 'view', card: frontCard, rootData: rootData }}" />
|
|
6
|
+
</view>
|
|
7
|
+
<view class="km-card-layout__face km-card-layout__face--back">
|
|
8
|
+
<template is="card-content" data="{{ idPrefix: 'view', card: backCard, rootData: rootData }}" />
|
|
11
9
|
</view>
|
|
12
10
|
</view>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<
|
|
11
|
+
<view wx:else class="km-card-layout__single">
|
|
12
|
+
<template is="card-content" data="{{ idPrefix: 'view', card: activeCard, rootData: rootData }}" />
|
|
13
|
+
</view>
|
|
14
|
+
<view wx:if="{{showToggle}}" class="km-card-layout__toggle" catchtap="onToggleTap">
|
|
15
|
+
<icon-element element="{{switch}}" > </icon-element>
|
|
16
|
+
<text class="km-card-layout__toggle-text">{{activeIndex === 0?'反面':'正面'}}</text>
|
|
17
|
+
</view>
|
|
18
|
+
</view>
|
|
19
|
+
</view>
|
|
20
|
+
|
|
21
|
+
<view class="km-card-layout layout-canvas-container" style="{{canvasCard.sizeStyle}}">
|
|
22
|
+
<view class="km-card-layout__item canvas-item">
|
|
23
|
+
<view class="km-card-layout__single">
|
|
24
|
+
<template is="card-content" data="{{ idPrefix: 'canvas', card: canvasCard, rootData: rootData }}" />
|
|
25
|
+
</view>
|
|
26
|
+
</view>
|
|
27
|
+
</view>
|
|
28
|
+
|
|
29
|
+
<wxml2canvas id="layout-canvas" container-class="layout-canvas-container" item-class="canvas-item"></wxml2canvas>
|
|
18
30
|
<share-canvas id="share-canvas"></share-canvas>
|
|
31
|
+
|
|
32
|
+
<template name="card-content">
|
|
33
|
+
<view wx:if="{{card}}" class="km-card canvas-item" style="{{card.cardStyle}}">
|
|
34
|
+
<image wx:if="{{card.backgroundImage}}" class="km-card__bg canvas-item" style="{{card.backgroundStyle}}" src="{{card.backgroundImage}}" mode="aspectFill" />
|
|
35
|
+
<block wx:for="{{card.elements}}" wx:key="id">
|
|
36
|
+
<template wx:if="{{item.visible !== false}}" is="render-element" data="{{el:item, rootData: rootData, idPrefix: idPrefix}}" />
|
|
37
|
+
</block>
|
|
38
|
+
</view>
|
|
39
|
+
</template>
|
|
40
|
+
|
|
19
41
|
<template name="render-element">
|
|
20
42
|
<block wx:if="{{el.type === 'image'}}">
|
|
21
|
-
<image-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
43
|
+
<image-element id="{{idPrefix}}-node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
22
44
|
</block>
|
|
23
45
|
<block wx:elif="{{el.type === 'icon'}}">
|
|
24
|
-
<icon-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
46
|
+
<icon-element id="{{idPrefix}}-node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
25
47
|
</block>
|
|
26
48
|
<block wx:elif="{{el.type === 'layout-panel'}}">
|
|
27
|
-
<layout-panel-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}">
|
|
49
|
+
<layout-panel-element id="{{idPrefix}}-node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}">
|
|
28
50
|
<block wx:for="{{el.children}}" wx:key="id">
|
|
29
|
-
<template is="render-element" data="{{el:item, rootData: rootData}}" />
|
|
51
|
+
<template is="render-element" data="{{el:item, rootData: rootData, idPrefix: idPrefix}}" />
|
|
30
52
|
</block>
|
|
31
53
|
</layout-panel-element>
|
|
32
54
|
</block>
|
|
33
55
|
<block wx:elif="{{el.type === 'custom'}}">
|
|
34
|
-
<custom-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
56
|
+
<custom-element id="{{idPrefix}}-node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
35
57
|
</block>
|
|
36
58
|
<block wx:else>
|
|
37
|
-
<text-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
59
|
+
<text-element id="{{idPrefix}}-node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
38
60
|
</block>
|
|
39
|
-
</template>
|
|
61
|
+
</template>
|
|
62
|
+
|
|
63
|
+
|
|
@@ -2,10 +2,66 @@
|
|
|
2
2
|
display: flex;
|
|
3
3
|
flex-direction: column;
|
|
4
4
|
position: relative;
|
|
5
|
+
perspective: 1200rpx;
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
.km-card-layout__item {
|
|
8
9
|
width: 100%;
|
|
10
|
+
position: relative;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.layout-canvas-container {
|
|
14
|
+
position: fixed;
|
|
15
|
+
left: -10000rpx;
|
|
16
|
+
top: 0;
|
|
17
|
+
opacity: 0;
|
|
18
|
+
pointer-events: none;
|
|
19
|
+
z-index: -1;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.km-card-layout__flip {
|
|
23
|
+
position: relative;
|
|
24
|
+
-webkit-transform-style: preserve-3d;
|
|
25
|
+
transform-style: preserve-3d;
|
|
26
|
+
transition: transform 420ms ease;
|
|
27
|
+
transform-origin: center;
|
|
28
|
+
will-change: transform;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.km-card-layout__flip.is-flipped {
|
|
32
|
+
transform: rotateY(180deg);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.km-card-layout__flip:not(.is-switching) .km-card-layout__face--back {
|
|
36
|
+
visibility: hidden;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.km-card-layout__flip.is-flipped:not(.is-switching) .km-card-layout__face--front {
|
|
40
|
+
visibility: hidden;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.km-card-layout__flip.is-flipped:not(.is-switching) .km-card-layout__face--back {
|
|
44
|
+
visibility: visible;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.km-card-layout__face {
|
|
48
|
+
position: absolute;
|
|
49
|
+
left: 0;
|
|
50
|
+
top: 0;
|
|
51
|
+
width: 100%;
|
|
52
|
+
height: 100%;
|
|
53
|
+
-webkit-backface-visibility: hidden;
|
|
54
|
+
backface-visibility: hidden;
|
|
55
|
+
-webkit-transform-style: preserve-3d;
|
|
56
|
+
transform-style: preserve-3d;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.km-card-layout__face--back {
|
|
60
|
+
transform: rotateY(180deg);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.km-card-layout__single {
|
|
64
|
+
position: relative;
|
|
9
65
|
}
|
|
10
66
|
|
|
11
67
|
.km-card {
|
|
@@ -15,6 +71,8 @@
|
|
|
15
71
|
color: inherit;
|
|
16
72
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
17
73
|
background: transparent;
|
|
74
|
+
-webkit-backface-visibility: hidden;
|
|
75
|
+
backface-visibility: hidden;
|
|
18
76
|
}
|
|
19
77
|
|
|
20
78
|
.km-card__bg {
|
|
@@ -25,3 +83,27 @@
|
|
|
25
83
|
height: 100%;
|
|
26
84
|
object-fit: cover;
|
|
27
85
|
}
|
|
86
|
+
|
|
87
|
+
.km-card-layout__toggle {
|
|
88
|
+
position: absolute;
|
|
89
|
+
top: 48rpx;
|
|
90
|
+
right: 20rpx;
|
|
91
|
+
z-index: 20;
|
|
92
|
+
padding: 8rpx 16rpx;
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
gap: 4rpx;
|
|
96
|
+
border-radius: 30px;
|
|
97
|
+
border: 0.5px solid #FFF;
|
|
98
|
+
color: #fff;
|
|
99
|
+
background: rgba(85, 85, 85, 0.30);
|
|
100
|
+
backdrop-filter: blur(4px);
|
|
101
|
+
-webkit-backdrop-filter: blur(4rpx);
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.km-card-layout__toggle-text {
|
|
106
|
+
color: #ffffff;
|
|
107
|
+
font-size: 24rpx;
|
|
108
|
+
line-height: 1;
|
|
109
|
+
}
|
package/package.json
CHANGED
|
@@ -9,13 +9,13 @@ import { ICON_CODE_MAP } from "../../icon-map";
|
|
|
9
9
|
|
|
10
10
|
const normalizeIconName = (name?: string) => {
|
|
11
11
|
if (!name) return "";
|
|
12
|
-
return name.startsWith("icon-") ? name.slice(5) : name;
|
|
12
|
+
return name.startsWith("layout-icon-") ? name.slice(5) : name;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
const buildIconClassName = (name?: string) => {
|
|
16
16
|
const normalized = normalizeIconName(name);
|
|
17
17
|
if (!normalized) return "";
|
|
18
|
-
return `icon-${normalized}`;
|
|
18
|
+
return `layout-icon-${normalized}`;
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
const buildIconCode = (name?: string) => {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<view class="km-node km-node--icon canvas-item" style="{{wrapperStyle}}">
|
|
2
|
-
<view class="km-node__icon
|
|
2
|
+
<view class="km-node__icon layoutIconFont {{iconClass}} canvas-item" style="{{contentStyle}}" data-icon="{{iconCode}}"></view>
|
|
3
3
|
</view>
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
@font-face {
|
|
2
2
|
font-family: "layoutIconFont"; /* Project id 5095635 */
|
|
3
|
-
src: url('//at.alicdn.com/t/c/
|
|
4
|
-
url('//at.alicdn.com/t/c/
|
|
5
|
-
url('//at.alicdn.com/t/c/
|
|
6
|
-
url('//at.alicdn.com/t/c/
|
|
3
|
+
src: url('//at.alicdn.com/t/c/font_5095635_0u3b33ft9ub.woff2?t=1770624313420') format('woff2'),
|
|
4
|
+
url('//at.alicdn.com/t/c/font_5095635_0u3b33ft9ub.woff?t=1770624313420') format('woff'),
|
|
5
|
+
url('//at.alicdn.com/t/c/font_5095635_0u3b33ft9ub.ttf?t=1770624313420') format('truetype'),
|
|
6
|
+
url('//at.alicdn.com/t/c/font_5095635_0u3b33ft9ub.svg?t=1770624313420#layoutIconFont') format('svg');
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
.layoutIconFont {
|
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
-moz-osx-font-smoothing: grayscale;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
.layout-icon-refresh:before {
|
|
18
|
+
content: "\e62b";
|
|
19
|
+
}
|
|
20
|
+
|
|
17
21
|
.layout-icon-round:before {
|
|
18
22
|
content: "\e608";
|
|
19
23
|
}
|
|
@@ -19,18 +19,20 @@ const EMPTY_COMPANY_DUTY: CompanyDuty = {
|
|
|
19
19
|
duty: "",
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
+
const SWITCH_ANIMATION_MS = 420;
|
|
23
|
+
const SWIPE_MIN_DISTANCE = 40;
|
|
24
|
+
const SWIPE_DIRECTION_RATIO = 1.2;
|
|
25
|
+
|
|
22
26
|
/**
|
|
23
|
-
*
|
|
27
|
+
* 规范�?moreCardInfo.company,保证长度始终为 2
|
|
24
28
|
*/
|
|
25
29
|
export function normalizeMoreCompany(data: AnyObject): AnyObject {
|
|
26
30
|
const origin = data.user?.moreCardInfo?.company;
|
|
27
31
|
|
|
28
|
-
// 不存在 / 不是数组 → 不处理
|
|
29
32
|
if (!Array.isArray(origin)) {
|
|
30
33
|
return data;
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
// 长度 === 0 → 不处理
|
|
34
36
|
if (origin.length === 0) {
|
|
35
37
|
return data;
|
|
36
38
|
}
|
|
@@ -58,6 +60,7 @@ type RenderElement = CardElement;
|
|
|
58
60
|
type RenderCard = {
|
|
59
61
|
id: string;
|
|
60
62
|
cardStyle: string;
|
|
63
|
+
sizeStyle: string;
|
|
61
64
|
backgroundImage?: string;
|
|
62
65
|
backgroundStyle: string;
|
|
63
66
|
elements: RenderElement[];
|
|
@@ -69,13 +72,25 @@ const pickCardId = (layout: any, idx: number) => {
|
|
|
69
72
|
};
|
|
70
73
|
|
|
71
74
|
const buildCards = (layouts: CardLayoutSchema[]) => {
|
|
72
|
-
return layouts.map((layout, idx) =>
|
|
73
|
-
|
|
74
|
-
cardStyle
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
return layouts.map((layout, idx) => {
|
|
76
|
+
const baseCardStyle = buildCardStyle(layout, "rpx");
|
|
77
|
+
const cardStyle = styleObjectToString(baseCardStyle, "rpx");
|
|
78
|
+
const sizeStyle = styleObjectToString(
|
|
79
|
+
{
|
|
80
|
+
width: baseCardStyle.width,
|
|
81
|
+
height: baseCardStyle.height,
|
|
82
|
+
},
|
|
83
|
+
"rpx",
|
|
84
|
+
);
|
|
85
|
+
return {
|
|
86
|
+
id: pickCardId(layouts[idx], idx),
|
|
87
|
+
cardStyle,
|
|
88
|
+
sizeStyle,
|
|
89
|
+
backgroundImage: layout.backgroundImage || "",
|
|
90
|
+
backgroundStyle: styleObjectToString(buildBackgroundStyle(layout, "rpx"), "rpx"),
|
|
91
|
+
elements: layout.children || [],
|
|
92
|
+
};
|
|
93
|
+
});
|
|
79
94
|
};
|
|
80
95
|
|
|
81
96
|
const nextTick = () =>
|
|
@@ -105,6 +120,20 @@ Component({
|
|
|
105
120
|
rootData: {} as Record<string, any>,
|
|
106
121
|
firstCard: [] as RenderCard[],
|
|
107
122
|
shareImage: "",
|
|
123
|
+
activeCard: null as RenderCard | null,
|
|
124
|
+
canvasCard: null as RenderCard | null,
|
|
125
|
+
frontCard: null as RenderCard | null,
|
|
126
|
+
backCard: null as RenderCard | null,
|
|
127
|
+
activeIndex: 0,
|
|
128
|
+
flipEnabled: false,
|
|
129
|
+
showToggle: false,
|
|
130
|
+
isFlipped: false,
|
|
131
|
+
isSwitching: false,
|
|
132
|
+
switch: {
|
|
133
|
+
name: "refresh",
|
|
134
|
+
size: 14,
|
|
135
|
+
style: "fill",
|
|
136
|
+
},
|
|
108
137
|
},
|
|
109
138
|
observers: {
|
|
110
139
|
layout() {
|
|
@@ -129,18 +158,119 @@ Component({
|
|
|
129
158
|
return self._fontReady;
|
|
130
159
|
},
|
|
131
160
|
rebuild() {
|
|
161
|
+
const self = this as any;
|
|
162
|
+
if (self._switchTimer) {
|
|
163
|
+
clearTimeout(self._switchTimer);
|
|
164
|
+
self._switchTimer = null;
|
|
165
|
+
}
|
|
132
166
|
const data = normalizeMoreCompany(this.data.data);
|
|
133
167
|
const layoutInput = hasCompanyDutyKey(this.data.layout)
|
|
134
168
|
? processCardLayout(this.data.layout, data as any)
|
|
135
169
|
: this.data.layout;
|
|
136
170
|
const rootData = handleSpecialFields(data as any);
|
|
137
171
|
if (!layoutInput.length) {
|
|
138
|
-
this.setData({
|
|
172
|
+
this.setData({
|
|
173
|
+
cards: [],
|
|
174
|
+
rootData,
|
|
175
|
+
activeCard: null,
|
|
176
|
+
canvasCard: null,
|
|
177
|
+
frontCard: null,
|
|
178
|
+
backCard: null,
|
|
179
|
+
activeIndex: 0,
|
|
180
|
+
flipEnabled: false,
|
|
181
|
+
showToggle: false,
|
|
182
|
+
isFlipped: false,
|
|
183
|
+
isSwitching: false,
|
|
184
|
+
});
|
|
139
185
|
return;
|
|
140
186
|
}
|
|
141
187
|
const normalizedLayouts = normalizeLayout(layoutInput);
|
|
142
188
|
const cards = buildCards(normalizedLayouts);
|
|
143
|
-
|
|
189
|
+
const activeIndex = 0;
|
|
190
|
+
const flipEnabled = cards.length > 1;
|
|
191
|
+
const activeCard = cards[activeIndex] || null;
|
|
192
|
+
const frontCard = cards[0] || null;
|
|
193
|
+
const backCard = cards[1] || null;
|
|
194
|
+
this.setData({
|
|
195
|
+
cards,
|
|
196
|
+
rootData,
|
|
197
|
+
firstCard: [cards[0]],
|
|
198
|
+
activeIndex,
|
|
199
|
+
activeCard,
|
|
200
|
+
canvasCard: activeCard,
|
|
201
|
+
frontCard,
|
|
202
|
+
backCard,
|
|
203
|
+
flipEnabled,
|
|
204
|
+
showToggle: flipEnabled,
|
|
205
|
+
isFlipped: false,
|
|
206
|
+
isSwitching: false,
|
|
207
|
+
});
|
|
208
|
+
},
|
|
209
|
+
|
|
210
|
+
handleToggleCard() {
|
|
211
|
+
const cards = this.data.cards;
|
|
212
|
+
if (!cards || cards.length < 2) return;
|
|
213
|
+
if (this.data.isSwitching) return;
|
|
214
|
+
|
|
215
|
+
const self = this as any;
|
|
216
|
+
if (self._switchTimer) {
|
|
217
|
+
clearTimeout(self._switchTimer);
|
|
218
|
+
self._switchTimer = null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const nextIndex = this.data.activeIndex === 0 ? 1 : 0;
|
|
222
|
+
this.setData({
|
|
223
|
+
activeIndex: nextIndex,
|
|
224
|
+
activeCard: cards[nextIndex],
|
|
225
|
+
canvasCard: cards[nextIndex],
|
|
226
|
+
isFlipped: nextIndex === 1,
|
|
227
|
+
isSwitching: true,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
self._switchTimer = setTimeout(() => {
|
|
231
|
+
self._switchTimer = null;
|
|
232
|
+
this.setData({ isSwitching: false });
|
|
233
|
+
}, SWITCH_ANIMATION_MS);
|
|
234
|
+
},
|
|
235
|
+
|
|
236
|
+
onToggleTap() {
|
|
237
|
+
this.handleToggleCard();
|
|
238
|
+
},
|
|
239
|
+
|
|
240
|
+
onTouchStart(event: WechatMiniprogram.TouchEvent) {
|
|
241
|
+
const touch = event.touches && event.touches[0];
|
|
242
|
+
if (!touch) return;
|
|
243
|
+
const self = this as any;
|
|
244
|
+
self._touchStartX = touch.clientX;
|
|
245
|
+
self._touchStartY = touch.clientY;
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
onTouchEnd(event: WechatMiniprogram.TouchEvent) {
|
|
249
|
+
const self = this as any;
|
|
250
|
+
const touch = event.changedTouches && event.changedTouches[0];
|
|
251
|
+
if (!touch) return;
|
|
252
|
+
|
|
253
|
+
const startX = self._touchStartX;
|
|
254
|
+
const startY = self._touchStartY;
|
|
255
|
+
self._touchStartX = null;
|
|
256
|
+
self._touchStartY = null;
|
|
257
|
+
|
|
258
|
+
if (typeof startX !== "number" || typeof startY !== "number") return;
|
|
259
|
+
|
|
260
|
+
const dx = touch.clientX - startX;
|
|
261
|
+
const dy = touch.clientY - startY;
|
|
262
|
+
const absDx = Math.abs(dx);
|
|
263
|
+
const absDy = Math.abs(dy);
|
|
264
|
+
|
|
265
|
+
if (absDx > SWIPE_MIN_DISTANCE && absDx > absDy * SWIPE_DIRECTION_RATIO) {
|
|
266
|
+
this.handleToggleCard();
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
onTouchCancel() {
|
|
271
|
+
const self = this as any;
|
|
272
|
+
self._touchStartX = null;
|
|
273
|
+
self._touchStartY = null;
|
|
144
274
|
},
|
|
145
275
|
|
|
146
276
|
async handleDrawCanvas(options?: { waitForReady?: boolean; skipDrawingGuard?: boolean }) {
|
|
@@ -166,16 +296,22 @@ Component({
|
|
|
166
296
|
self._isDrawing = false;
|
|
167
297
|
}
|
|
168
298
|
}
|
|
169
|
-
},
|
|
170
|
-
|
|
171
|
-
async handleDrawShareCanvas() {
|
|
299
|
+
}, async handleDrawShareCanvas() {
|
|
172
300
|
const self = this as any;
|
|
173
301
|
if (self._isDrawing) return;
|
|
174
302
|
self._isDrawing = true;
|
|
303
|
+
let previousCanvasCard: RenderCard | null | undefined;
|
|
175
304
|
try {
|
|
176
305
|
// wait for setData / component render
|
|
177
306
|
await nextTick();
|
|
178
307
|
|
|
308
|
+
const frontCard = this.data.frontCard || this.data.activeCard;
|
|
309
|
+
previousCanvasCard = this.data.canvasCard;
|
|
310
|
+
if (frontCard && frontCard !== previousCanvasCard) {
|
|
311
|
+
await new Promise<void>((resolve) => this.setData({ canvasCard: frontCard }, resolve));
|
|
312
|
+
await nextTick();
|
|
313
|
+
}
|
|
314
|
+
|
|
179
315
|
const layoutPath = await this.handleDrawCanvas({ waitForReady: false, skipDrawingGuard: true });
|
|
180
316
|
if (!layoutPath) return;
|
|
181
317
|
|
|
@@ -193,18 +329,24 @@ Component({
|
|
|
193
329
|
}
|
|
194
330
|
return filePath;
|
|
195
331
|
} finally {
|
|
332
|
+
if (previousCanvasCard && previousCanvasCard !== this.data.canvasCard) {
|
|
333
|
+
this.setData({ canvasCard: previousCanvasCard });
|
|
334
|
+
}
|
|
196
335
|
self._isDrawing = false;
|
|
197
336
|
}
|
|
198
337
|
},
|
|
199
|
-
|
|
200
338
|
async loadFont() {
|
|
201
339
|
await wx.loadFontFace({
|
|
202
340
|
global: true,
|
|
203
341
|
family: "layoutIconFont",
|
|
204
342
|
scopes: ["native"],
|
|
205
|
-
|
|
206
|
-
source: "https://at.alicdn.com/t/c/font_5095635_ztv7ro0zm59.ttf?t=1766563440291",
|
|
343
|
+
source: "https://at.alicdn.com/t/c/font_5095635_0u3b33ft9ub.ttf?t=1770624313420",
|
|
207
344
|
});
|
|
208
345
|
},
|
|
209
346
|
},
|
|
210
347
|
});
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
|
|
@@ -1,39 +1,63 @@
|
|
|
1
|
-
<
|
|
2
|
-
<
|
|
3
|
-
<view class="km-card-
|
|
4
|
-
<view class="km-card-
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
</block>
|
|
10
|
-
</view>
|
|
1
|
+
<view class="km-card-layout layout-view-container" bindtouchstart="onTouchStart" bindtouchend="onTouchEnd" bindtouchcancel="onTouchCancel">
|
|
2
|
+
<view class="km-card-layout__item canvas-item">
|
|
3
|
+
<view wx:if="{{flipEnabled}}" class="km-card-layout__flip {{isFlipped ? 'is-flipped' : ''}} {{isSwitching ? 'is-switching' : ''}}" style="{{frontCard.sizeStyle}}">
|
|
4
|
+
<view class="km-card-layout__face km-card-layout__face--front">
|
|
5
|
+
<template is="card-content" data="{{ idPrefix: 'view', card: frontCard, rootData: rootData }}" />
|
|
6
|
+
</view>
|
|
7
|
+
<view class="km-card-layout__face km-card-layout__face--back">
|
|
8
|
+
<template is="card-content" data="{{ idPrefix: 'view', card: backCard, rootData: rootData }}" />
|
|
11
9
|
</view>
|
|
12
10
|
</view>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
<
|
|
11
|
+
<view wx:else class="km-card-layout__single">
|
|
12
|
+
<template is="card-content" data="{{ idPrefix: 'view', card: activeCard, rootData: rootData }}" />
|
|
13
|
+
</view>
|
|
14
|
+
<view wx:if="{{showToggle}}" class="km-card-layout__toggle" catchtap="onToggleTap">
|
|
15
|
+
<icon-element element="{{switch}}" > </icon-element>
|
|
16
|
+
<text class="km-card-layout__toggle-text">{{activeIndex === 0?'反面':'正面'}}</text>
|
|
17
|
+
</view>
|
|
18
|
+
</view>
|
|
19
|
+
</view>
|
|
20
|
+
|
|
21
|
+
<view class="km-card-layout layout-canvas-container" style="{{canvasCard.sizeStyle}}">
|
|
22
|
+
<view class="km-card-layout__item canvas-item">
|
|
23
|
+
<view class="km-card-layout__single">
|
|
24
|
+
<template is="card-content" data="{{ idPrefix: 'canvas', card: canvasCard, rootData: rootData }}" />
|
|
25
|
+
</view>
|
|
26
|
+
</view>
|
|
27
|
+
</view>
|
|
28
|
+
|
|
29
|
+
<wxml2canvas id="layout-canvas" container-class="layout-canvas-container" item-class="canvas-item"></wxml2canvas>
|
|
18
30
|
<share-canvas id="share-canvas"></share-canvas>
|
|
31
|
+
|
|
32
|
+
<template name="card-content">
|
|
33
|
+
<view wx:if="{{card}}" class="km-card canvas-item" style="{{card.cardStyle}}">
|
|
34
|
+
<image wx:if="{{card.backgroundImage}}" class="km-card__bg canvas-item" style="{{card.backgroundStyle}}" src="{{card.backgroundImage}}" mode="aspectFill" />
|
|
35
|
+
<block wx:for="{{card.elements}}" wx:key="id">
|
|
36
|
+
<template wx:if="{{item.visible !== false}}" is="render-element" data="{{el:item, rootData: rootData, idPrefix: idPrefix}}" />
|
|
37
|
+
</block>
|
|
38
|
+
</view>
|
|
39
|
+
</template>
|
|
40
|
+
|
|
19
41
|
<template name="render-element">
|
|
20
42
|
<block wx:if="{{el.type === 'image'}}">
|
|
21
|
-
<image-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
43
|
+
<image-element id="{{idPrefix}}-node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
22
44
|
</block>
|
|
23
45
|
<block wx:elif="{{el.type === 'icon'}}">
|
|
24
|
-
<icon-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
46
|
+
<icon-element id="{{idPrefix}}-node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
25
47
|
</block>
|
|
26
48
|
<block wx:elif="{{el.type === 'layout-panel'}}">
|
|
27
|
-
<layout-panel-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}">
|
|
49
|
+
<layout-panel-element id="{{idPrefix}}-node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}">
|
|
28
50
|
<block wx:for="{{el.children}}" wx:key="id">
|
|
29
|
-
<template is="render-element" data="{{el:item, rootData: rootData}}" />
|
|
51
|
+
<template is="render-element" data="{{el:item, rootData: rootData, idPrefix: idPrefix}}" />
|
|
30
52
|
</block>
|
|
31
53
|
</layout-panel-element>
|
|
32
54
|
</block>
|
|
33
55
|
<block wx:elif="{{el.type === 'custom'}}">
|
|
34
|
-
<custom-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
56
|
+
<custom-element id="{{idPrefix}}-node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
35
57
|
</block>
|
|
36
58
|
<block wx:else>
|
|
37
|
-
<text-element id="node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
59
|
+
<text-element id="{{idPrefix}}-node-{{el.id}}" class="canvas-item" data-component="{{true}}" element="{{el}}" rootData="{{rootData}}" />
|
|
38
60
|
</block>
|
|
39
|
-
</template>
|
|
61
|
+
</template>
|
|
62
|
+
|
|
63
|
+
|
|
@@ -2,10 +2,66 @@
|
|
|
2
2
|
display: flex;
|
|
3
3
|
flex-direction: column;
|
|
4
4
|
position: relative;
|
|
5
|
+
perspective: 1200rpx;
|
|
5
6
|
}
|
|
6
7
|
|
|
7
8
|
.km-card-layout__item {
|
|
8
9
|
width: 100%;
|
|
10
|
+
position: relative;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.layout-canvas-container {
|
|
14
|
+
position: fixed;
|
|
15
|
+
left: -10000rpx;
|
|
16
|
+
top: 0;
|
|
17
|
+
opacity: 0;
|
|
18
|
+
pointer-events: none;
|
|
19
|
+
z-index: -1;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.km-card-layout__flip {
|
|
23
|
+
position: relative;
|
|
24
|
+
-webkit-transform-style: preserve-3d;
|
|
25
|
+
transform-style: preserve-3d;
|
|
26
|
+
transition: transform 420ms ease;
|
|
27
|
+
transform-origin: center;
|
|
28
|
+
will-change: transform;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.km-card-layout__flip.is-flipped {
|
|
32
|
+
transform: rotateY(180deg);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.km-card-layout__flip:not(.is-switching) .km-card-layout__face--back {
|
|
36
|
+
visibility: hidden;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.km-card-layout__flip.is-flipped:not(.is-switching) .km-card-layout__face--front {
|
|
40
|
+
visibility: hidden;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.km-card-layout__flip.is-flipped:not(.is-switching) .km-card-layout__face--back {
|
|
44
|
+
visibility: visible;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.km-card-layout__face {
|
|
48
|
+
position: absolute;
|
|
49
|
+
left: 0;
|
|
50
|
+
top: 0;
|
|
51
|
+
width: 100%;
|
|
52
|
+
height: 100%;
|
|
53
|
+
-webkit-backface-visibility: hidden;
|
|
54
|
+
backface-visibility: hidden;
|
|
55
|
+
-webkit-transform-style: preserve-3d;
|
|
56
|
+
transform-style: preserve-3d;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.km-card-layout__face--back {
|
|
60
|
+
transform: rotateY(180deg);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.km-card-layout__single {
|
|
64
|
+
position: relative;
|
|
9
65
|
}
|
|
10
66
|
|
|
11
67
|
.km-card {
|
|
@@ -15,6 +71,8 @@
|
|
|
15
71
|
color: inherit;
|
|
16
72
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
17
73
|
background: transparent;
|
|
74
|
+
-webkit-backface-visibility: hidden;
|
|
75
|
+
backface-visibility: hidden;
|
|
18
76
|
}
|
|
19
77
|
|
|
20
78
|
.km-card__bg {
|
|
@@ -25,3 +83,27 @@
|
|
|
25
83
|
height: 100%;
|
|
26
84
|
object-fit: cover;
|
|
27
85
|
}
|
|
86
|
+
|
|
87
|
+
.km-card-layout__toggle {
|
|
88
|
+
position: absolute;
|
|
89
|
+
top: 48rpx;
|
|
90
|
+
right: 20rpx;
|
|
91
|
+
z-index: 20;
|
|
92
|
+
padding: 8rpx 16rpx;
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
gap: 4rpx;
|
|
96
|
+
border-radius: 30px;
|
|
97
|
+
border: 0.5px solid #FFF;
|
|
98
|
+
color: #fff;
|
|
99
|
+
background: rgba(85, 85, 85, 0.30);
|
|
100
|
+
backdrop-filter: blur(4px);
|
|
101
|
+
-webkit-backdrop-filter: blur(4rpx);
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.km-card-layout__toggle-text {
|
|
106
|
+
color: #ffffff;
|
|
107
|
+
font-size: 24rpx;
|
|
108
|
+
line-height: 1;
|
|
109
|
+
}
|