@rxdrag/website-lib-core 0.0.8 → 0.0.10
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/package.json +4 -4
- package/src/component-logic/collapse.ts +61 -0
- package/src/component-logic/index.ts +1 -0
- package/src/component-logic/modal.ts +14 -14
- package/src/component-logic/motion.ts +7 -7
- package/src/component-logic/popover.ts +9 -9
- package/src/controller/CollapseController.ts +130 -0
- package/src/controller/ModalController.ts +19 -19
- package/src/controller/{popup.ts → OpenableController.ts} +53 -37
- package/src/controller/PageLoader.ts +3 -13
- package/src/controller/PopoverController.ts +13 -13
- package/src/controller/TabsController.ts +1 -1
- package/src/controller/consts.ts +9 -6
- package/src/controller/index.ts +1 -0
- package/src/entify/IEntify.ts +1 -1
- package/src/entify/lib/newQueryProductOptions.ts +2 -11
- package/src/entify/lib/queryOneProductBySlug.ts +52 -10
- package/src/entify/lib/queryOneTheme.ts +1 -7
- package/src/entify/view-model/funcs.ts +0 -16
- package/src/lib/utils.ts +30 -14
- package/src/motion/consts.ts +3 -3
- package/src/motion/normalizePopupAnimation.ts +3 -3
- package/src/motion/types.ts +1 -1
- package/src/react/components/ContactForm/index.tsx +13 -5
- package/src/react/components/Icon/index.tsx +8 -4
- package/src/react/components/ProductCard/ProductCard.tsx +2 -1
- package/src/react/components/ProductCard/ProductCta/index.tsx +13 -12
- package/src/react/components/ProductCard/ProductView.tsx +3 -2
- package/src/react/components/ToTop/index.tsx +1 -1
- package/src/react/components/ToTop.tsx +1 -1
- package/src/react/hooks/useScroll.ts +12 -11
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DATA_MOTION_OPENABLE, OpenableAnimationConfig } from "../motion";
|
|
2
2
|
import { applyAnimation } from "./applyAnimation";
|
|
3
3
|
import { gsap } from "gsap/dist/gsap";
|
|
4
4
|
import {
|
|
5
5
|
EVENT_OPEN,
|
|
6
6
|
EVENT_CLOSE,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
DATA_OPENABLE,
|
|
8
|
+
DATA_OPENABLE_ROLE,
|
|
9
|
+
OpenAble,
|
|
10
10
|
EVENT_SELECT,
|
|
11
11
|
EVENT_UNSELECT,
|
|
12
12
|
} from "./consts";
|
|
@@ -126,14 +126,14 @@ export class EventBus {
|
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
export class
|
|
129
|
+
export class OpenableController {
|
|
130
130
|
constructor(protected doc: Document | undefined) {}
|
|
131
131
|
protected unmountHandlers: (() => void)[] = [];
|
|
132
132
|
protected eventBus = new EventBus();
|
|
133
133
|
|
|
134
134
|
mount() {
|
|
135
135
|
this.unmount();
|
|
136
|
-
this.
|
|
136
|
+
this.initOpenableAnimations();
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
unmount() {
|
|
@@ -142,38 +142,38 @@ export class PopupController {
|
|
|
142
142
|
}
|
|
143
143
|
/**
|
|
144
144
|
* 打开弹出层
|
|
145
|
-
* @param
|
|
145
|
+
* @param openableKey - 弹出层的唯一标识
|
|
146
146
|
* @param target - 触发打开的目标元素
|
|
147
147
|
*/
|
|
148
|
-
open = (
|
|
148
|
+
open = (openableKey: string, target: HTMLElement): void => {
|
|
149
149
|
if (!this.doc) return;
|
|
150
150
|
|
|
151
151
|
try {
|
|
152
152
|
// 查找 Modal 容器
|
|
153
|
-
const modalContainer = this.
|
|
153
|
+
const modalContainer = this.getOpenableContainer(openableKey);
|
|
154
154
|
if (modalContainer) {
|
|
155
155
|
modalContainer.classList.add("open");
|
|
156
|
-
this.eventBus.emit(EVENT_OPEN, { key:
|
|
156
|
+
this.eventBus.emit(EVENT_OPEN, { key: openableKey, target });
|
|
157
157
|
} else {
|
|
158
|
-
console.warn(`未找到弹出层: ${
|
|
158
|
+
console.warn(`未找到弹出层: ${openableKey}`);
|
|
159
159
|
}
|
|
160
160
|
} catch (error) {
|
|
161
|
-
console.error(`打开弹出层失败: ${
|
|
161
|
+
console.error(`打开弹出层失败: ${openableKey}`, error);
|
|
162
162
|
}
|
|
163
163
|
};
|
|
164
164
|
|
|
165
165
|
/**
|
|
166
166
|
* 关闭弹出层
|
|
167
|
-
* @param
|
|
167
|
+
* @param openableKey - 弹出层的唯一标识
|
|
168
168
|
* @param target - 可选的目标元素,如果提供则使用该元素,否则查找容器
|
|
169
169
|
*/
|
|
170
|
-
close = (
|
|
170
|
+
close = (openableKey: string, target?: HTMLElement): void => {
|
|
171
171
|
if (!this.doc) return;
|
|
172
172
|
|
|
173
173
|
try {
|
|
174
|
-
const container = target || this.
|
|
174
|
+
const container = target || this.getOpenableContainer(openableKey);
|
|
175
175
|
if (!container) {
|
|
176
|
-
console.warn(`找不到弹出层容器: ${
|
|
176
|
+
console.warn(`找不到弹出层容器: ${openableKey}`);
|
|
177
177
|
return;
|
|
178
178
|
}
|
|
179
179
|
|
|
@@ -182,28 +182,30 @@ export class PopupController {
|
|
|
182
182
|
|
|
183
183
|
// 触发关闭事件
|
|
184
184
|
this.eventBus.emit(EVENT_CLOSE, {
|
|
185
|
-
key:
|
|
185
|
+
key: openableKey,
|
|
186
186
|
target: container,
|
|
187
187
|
});
|
|
188
188
|
} catch (error) {
|
|
189
|
-
console.error(`关闭弹出层失败: ${
|
|
189
|
+
console.error(`关闭弹出层失败: ${openableKey}`, error);
|
|
190
190
|
}
|
|
191
191
|
};
|
|
192
192
|
|
|
193
193
|
/**
|
|
194
194
|
* 获取弹出层容器元素
|
|
195
|
-
* @param
|
|
195
|
+
* @param openableKey - 弹出层的唯一标识
|
|
196
196
|
* @returns 弹出层容器元素,如果未找到则返回undefined
|
|
197
197
|
*/
|
|
198
|
-
|
|
198
|
+
getOpenableContainer = (openableKey: string): HTMLElement | undefined => {
|
|
199
199
|
if (!this.doc) return undefined;
|
|
200
200
|
|
|
201
201
|
try {
|
|
202
202
|
return this.doc.querySelector(
|
|
203
|
-
`[${
|
|
203
|
+
`[${DATA_OPENABLE}="${openableKey}"][${DATA_OPENABLE_ROLE}="${OpenAble.ModalContainer}"],
|
|
204
|
+
[${DATA_OPENABLE}="${openableKey}"][${DATA_OPENABLE_ROLE}="${OpenAble.PopoverContainer}"],
|
|
205
|
+
[${DATA_OPENABLE}="${openableKey}"][${DATA_OPENABLE_ROLE}="${OpenAble.CollapseContainer}"]`
|
|
204
206
|
) as HTMLElement | undefined;
|
|
205
207
|
} catch (error) {
|
|
206
|
-
console.error(`获取弹出层容器失败: ${
|
|
208
|
+
console.error(`获取弹出层容器失败: ${openableKey}`, error);
|
|
207
209
|
return undefined;
|
|
208
210
|
}
|
|
209
211
|
};
|
|
@@ -212,22 +214,36 @@ export class PopupController {
|
|
|
212
214
|
* 初始化弹窗动画
|
|
213
215
|
* @returns 清理函数
|
|
214
216
|
*/
|
|
215
|
-
|
|
217
|
+
initOpenableAnimations = () => {
|
|
216
218
|
const unsubscribe = this.onOpenAll((event) => {
|
|
217
219
|
const openResponseElements = this.doc?.querySelectorAll(
|
|
218
|
-
`[${
|
|
220
|
+
`[${DATA_MOTION_OPENABLE}]`
|
|
221
|
+
);
|
|
222
|
+
const containerElement = this.getOpenableContainer(event.key);
|
|
223
|
+
//处理循环嵌套的情况
|
|
224
|
+
const subContainers = containerElement?.querySelectorAll(
|
|
225
|
+
`[${DATA_OPENABLE_ROLE}="${OpenAble.CollapseContainer}"],
|
|
226
|
+
[${DATA_OPENABLE_ROLE}="${OpenAble.ModalContainer}"],
|
|
227
|
+
[${DATA_OPENABLE_ROLE}="${OpenAble.PopoverContainer}"]`
|
|
219
228
|
);
|
|
220
|
-
const containerElement = this.getPopupContainer(event.key);
|
|
221
229
|
//响应open事件
|
|
222
230
|
openResponseElements?.forEach((element) => {
|
|
231
|
+
let isInSubContainer = false;
|
|
232
|
+
subContainers?.forEach((subContainer) => {
|
|
233
|
+
if (subContainer.contains(element)) {
|
|
234
|
+
isInSubContainer = true;
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
});
|
|
223
238
|
if (
|
|
224
239
|
this.doc?.defaultView &&
|
|
225
240
|
element instanceof this.doc.defaultView?.HTMLElement &&
|
|
226
|
-
containerElement?.contains(element)
|
|
241
|
+
containerElement?.contains(element) &&
|
|
242
|
+
!isInSubContainer
|
|
227
243
|
) {
|
|
228
|
-
if (element.dataset.
|
|
229
|
-
const animation = JSON.parse(element.dataset.
|
|
230
|
-
|
|
|
244
|
+
if (element.dataset.motionOpenable) {
|
|
245
|
+
const animation = JSON.parse(element.dataset.motionOpenable) as
|
|
246
|
+
| OpenableAnimationConfig
|
|
231
247
|
| undefined;
|
|
232
248
|
if (animation?.initial) {
|
|
233
249
|
applyInitialState(element, animation.initial);
|
|
@@ -241,7 +257,7 @@ export class PopupController {
|
|
|
241
257
|
|
|
242
258
|
return () => {
|
|
243
259
|
const closeResponseElements = this.doc?.querySelectorAll(
|
|
244
|
-
`[${
|
|
260
|
+
`[${DATA_MOTION_OPENABLE}]`
|
|
245
261
|
);
|
|
246
262
|
|
|
247
263
|
//响应close事件
|
|
@@ -251,11 +267,11 @@ export class PopupController {
|
|
|
251
267
|
element instanceof this.doc?.defaultView.HTMLElement
|
|
252
268
|
) {
|
|
253
269
|
if (
|
|
254
|
-
element.dataset.
|
|
270
|
+
element.dataset.motionOpenable &&
|
|
255
271
|
containerElement?.contains(element)
|
|
256
272
|
) {
|
|
257
|
-
const animation = JSON.parse(element.dataset.
|
|
258
|
-
|
|
|
273
|
+
const animation = JSON.parse(element.dataset.motionOpenable) as
|
|
274
|
+
| OpenableAnimationConfig
|
|
259
275
|
| undefined;
|
|
260
276
|
if (animation?.close) {
|
|
261
277
|
// 首先终止该元素上可能正在进行的所有动画(包括open动画)
|
|
@@ -278,22 +294,22 @@ export class PopupController {
|
|
|
278
294
|
};
|
|
279
295
|
|
|
280
296
|
public onOpen = (
|
|
281
|
-
|
|
297
|
+
openableKey: string,
|
|
282
298
|
callback: (event: PopupEvent) => VoidFunction | void
|
|
283
299
|
): (() => void) => {
|
|
284
300
|
return this.onOpenAll((event) => {
|
|
285
|
-
if (event.key ===
|
|
301
|
+
if (event.key === openableKey) {
|
|
286
302
|
return callback(event);
|
|
287
303
|
}
|
|
288
304
|
});
|
|
289
305
|
};
|
|
290
306
|
|
|
291
307
|
public onClose = (
|
|
292
|
-
|
|
308
|
+
openableKey: string,
|
|
293
309
|
callback: (event: PopupEvent) => void
|
|
294
310
|
) => {
|
|
295
311
|
return this.onCloseAll((event) => {
|
|
296
|
-
if (event.key ===
|
|
312
|
+
if (event.key === openableKey) {
|
|
297
313
|
callback(event);
|
|
298
314
|
}
|
|
299
315
|
});
|
|
@@ -93,19 +93,9 @@ export class PageLoader implements IPageLoader {
|
|
|
93
93
|
// 只监听一个事件,优先使用 astro:page-load
|
|
94
94
|
if (typeof window !== "undefined") {
|
|
95
95
|
// 在客户端环境中
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
) {
|
|
100
|
-
// 如果文档已加载完成,立即执行一次
|
|
101
|
-
setTimeout(handleEvent, 0);
|
|
102
|
-
} else {
|
|
103
|
-
// 否则等待 DOMContentLoaded 事件
|
|
104
|
-
this.doc.addEventListener("DOMContentLoaded", handleEvent, {
|
|
105
|
-
once: true,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
96
|
+
this.doc.addEventListener("astro:page-load", handleEvent, {
|
|
97
|
+
once: true,
|
|
98
|
+
});
|
|
109
99
|
// 只监听页面转场事件
|
|
110
100
|
this.doc.addEventListener("astro:after-swap", handleEvent);
|
|
111
101
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { DATA_OPENABLE, DATA_OPENABLE_ROLE, OpenAble } from "./consts";
|
|
2
|
+
import { OpenableController } from "./OpenableController";
|
|
3
3
|
|
|
4
|
-
export class PopoverController extends
|
|
4
|
+
export class PopoverController extends OpenableController {
|
|
5
5
|
private static instances: Record<string, PopoverController> = {};
|
|
6
6
|
private constructor(doc?: Document) {
|
|
7
7
|
super(doc);
|
|
@@ -47,15 +47,15 @@ export class PopoverController extends PopupController {
|
|
|
47
47
|
//console.log("====> mount popover", this.doc);
|
|
48
48
|
super.mount();
|
|
49
49
|
// 获取所有的 Popover 实例
|
|
50
|
-
const popups = this.doc?.querySelectorAll(`[${
|
|
50
|
+
const popups = this.doc?.querySelectorAll(`[${DATA_OPENABLE}]`);
|
|
51
51
|
popups?.forEach((popup) => {
|
|
52
|
-
const
|
|
52
|
+
const openableKey = popup.getAttribute(DATA_OPENABLE);
|
|
53
53
|
//处理鼠标交互事件
|
|
54
|
-
if (
|
|
54
|
+
if (openableKey && popup) {
|
|
55
55
|
if (
|
|
56
|
-
popup.getAttribute(
|
|
56
|
+
popup.getAttribute(DATA_OPENABLE_ROLE) === OpenAble.PopoverContainer
|
|
57
57
|
) {
|
|
58
|
-
const unsub = this.initPopover(
|
|
58
|
+
const unsub = this.initPopover(openableKey, popup as HTMLElement);
|
|
59
59
|
this.unmountHandlers.push(unsub);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -68,12 +68,12 @@ export class PopoverController extends PopupController {
|
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* 初始化Popover的鼠标交互事件
|
|
71
|
-
* @param
|
|
71
|
+
* @param openableKey - 弹出层的唯一标识
|
|
72
72
|
* @param element - 弹出层的 DOM 元素
|
|
73
73
|
* @returns 清理函数,用于移除事件监听器
|
|
74
74
|
*/
|
|
75
75
|
public initPopover = (
|
|
76
|
-
|
|
76
|
+
openableKey: string,
|
|
77
77
|
element: HTMLElement
|
|
78
78
|
): (() => void) => {
|
|
79
79
|
if (!this.doc) return () => {};
|
|
@@ -81,11 +81,11 @@ export class PopoverController extends PopupController {
|
|
|
81
81
|
try {
|
|
82
82
|
// 创建新的事件处理函数
|
|
83
83
|
const handleMouseEnter = () => {
|
|
84
|
-
this.open(
|
|
84
|
+
this.open(openableKey, element);
|
|
85
85
|
};
|
|
86
86
|
|
|
87
87
|
const handleMouseLeave = () => {
|
|
88
|
-
this.close(
|
|
88
|
+
this.close(openableKey);
|
|
89
89
|
};
|
|
90
90
|
|
|
91
91
|
// 添加新的事件监听器
|
|
@@ -104,7 +104,7 @@ export class PopoverController extends PopupController {
|
|
|
104
104
|
element.removeEventListener("touchend", handleMouseLeave, options as EventListenerOptions);
|
|
105
105
|
};
|
|
106
106
|
} catch (error) {
|
|
107
|
-
console.error(`初始化Popover事件失败: ${
|
|
107
|
+
console.error(`初始化Popover事件失败: ${openableKey}`, error);
|
|
108
108
|
return () => {};
|
|
109
109
|
}
|
|
110
110
|
};
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
import { AnimationConfig } from "../motion";
|
|
9
9
|
import { applyAnimation } from "./applyAnimation";
|
|
10
10
|
import { EVENT_SELECT, EVENT_UNSELECT } from "./consts";
|
|
11
|
-
import { EventBus, SelectionEvent } from "./
|
|
11
|
+
import { EventBus, SelectionEvent } from "./OpenableController";
|
|
12
12
|
|
|
13
13
|
export class TabsController {
|
|
14
14
|
private static instances: Record<string, TabsController> = {};
|
package/src/controller/consts.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
//弹层ID
|
|
2
|
-
export const
|
|
2
|
+
export const DATA_OPENABLE = "data-openable";
|
|
3
3
|
|
|
4
|
-
//弹层角色,取值:
|
|
5
|
-
export const
|
|
4
|
+
//弹层角色,取值:Openable
|
|
5
|
+
export const DATA_OPENABLE_ROLE = "data-openable-role";
|
|
6
6
|
|
|
7
7
|
//弹层CTA,用于跟踪用户点击行为
|
|
8
8
|
export const DATA_POPUP_CTA = "data-popup-cta";
|
|
@@ -10,19 +10,22 @@ export const DATA_POPUP_CTA = "data-popup-cta";
|
|
|
10
10
|
//已经进入过视窗
|
|
11
11
|
export const DATA_VIEWPORT_ENTERED = "data-viewport-entered";
|
|
12
12
|
|
|
13
|
-
export enum
|
|
13
|
+
export enum OpenAble {
|
|
14
14
|
PopoverContainer = "popover-container",
|
|
15
15
|
PopoverPanel = "popover-panel",
|
|
16
16
|
ModalContainer = "modal-container",
|
|
17
17
|
ModalTrigger = "modal-trigger",
|
|
18
18
|
ModalPanel = "modal-panel",
|
|
19
19
|
ModalCloser = "modal-closer",
|
|
20
|
+
CollapseContainer = "collapse-container",
|
|
21
|
+
CollapsePanel = "collapse-panel",
|
|
22
|
+
CollapseTrigger = "collapse-trigger",
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
/** 弹出层打开事件名称 */
|
|
23
|
-
export const EVENT_OPEN = "
|
|
26
|
+
export const EVENT_OPEN = "openable-open";
|
|
24
27
|
/** 弹出层关闭事件名称 */
|
|
25
|
-
export const EVENT_CLOSE = "
|
|
28
|
+
export const EVENT_CLOSE = "openable-close";
|
|
26
29
|
|
|
27
30
|
/** 元素选中事件名称,比如tab切换 */
|
|
28
31
|
export const EVENT_SELECT = "element-select";
|
package/src/controller/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ export * from "./utils";
|
|
|
3
3
|
export * from "./ModalController";
|
|
4
4
|
export * from "./AnimateController";
|
|
5
5
|
export * from "./AosController";
|
|
6
|
+
export * from "./CollapseController";
|
|
6
7
|
export * from "./PopoverController";
|
|
7
8
|
export * from "./PageLoader";
|
|
8
9
|
export * from "./TabsController";
|
package/src/entify/IEntify.ts
CHANGED
|
@@ -42,7 +42,7 @@ export interface IEntify {
|
|
|
42
42
|
|
|
43
43
|
getPostPaths(): Promise<unknown>;
|
|
44
44
|
|
|
45
|
-
getPostBySlug(slug: string, coverSize: TSize | undefined): Promise<
|
|
45
|
+
getPostBySlug(slug: string, coverSize: TSize | undefined): Promise<TPost | undefined>;
|
|
46
46
|
|
|
47
47
|
getPostSlugs(): Promise<Array<string | undefined>>;
|
|
48
48
|
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
MediaOnProductFields,
|
|
8
8
|
AttachmentOnProductQueryOptions,
|
|
9
9
|
AttachmentOnProductFields,
|
|
10
|
-
ProductRelatedPivotQueryOptions,
|
|
11
10
|
ProductCategoryFields,
|
|
12
11
|
} from "@rxdrag/rxcms-models";
|
|
13
12
|
import { TSize } from "../types";
|
|
@@ -52,6 +51,8 @@ export function newQueryProductOptions(imagSize?: TSize) {
|
|
|
52
51
|
ProductFields.extends,
|
|
53
52
|
ProductFields.description,
|
|
54
53
|
ProductFields.features,
|
|
54
|
+
ProductFields.relatedSlugs,
|
|
55
|
+
ProductFields.relatedSlugs,
|
|
55
56
|
])
|
|
56
57
|
.meta(newPageMetaOptions())
|
|
57
58
|
.mediaPivots(creatProductMediaOptions(imagSize))
|
|
@@ -71,16 +72,6 @@ export function newQueryProductOptions(imagSize?: TSize) {
|
|
|
71
72
|
]).file(["url"])
|
|
72
73
|
)
|
|
73
74
|
)
|
|
74
|
-
.relatedPivot(
|
|
75
|
-
new ProductRelatedPivotQueryOptions().target(
|
|
76
|
-
new ProductQueryOptions()
|
|
77
|
-
.title()
|
|
78
|
-
.shortTitle()
|
|
79
|
-
.slug()
|
|
80
|
-
.description()
|
|
81
|
-
.mediaPivots(creatProductMediaOptions())
|
|
82
|
-
)
|
|
83
|
-
)
|
|
84
75
|
.category([
|
|
85
76
|
ProductCategoryFields.id,
|
|
86
77
|
ProductCategoryFields.slug,
|
|
@@ -1,21 +1,63 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Product,
|
|
3
|
+
ProductBoolExp,
|
|
4
|
+
ProductOrderBy,
|
|
5
|
+
ProductDistinctExp,
|
|
6
|
+
} from "@rxdrag/rxcms-models";
|
|
2
7
|
import { newQueryProductOptions } from "./newQueryProductOptions";
|
|
3
8
|
import { queryOneEntity } from "./queryOneEntity";
|
|
4
9
|
import { EnvVariables, TSize } from "../types";
|
|
5
|
-
import { TProduct } from "../view-model";
|
|
10
|
+
import { productToViewModel, TProduct } from "../view-model";
|
|
11
|
+
import { queryEntityList } from "./queryEntityList";
|
|
6
12
|
|
|
7
|
-
export async function queryOneProductBySlug(
|
|
13
|
+
export async function queryOneProductBySlug(
|
|
14
|
+
slug: string,
|
|
15
|
+
imageSize: TSize | undefined,
|
|
16
|
+
envVariables: EnvVariables
|
|
17
|
+
) {
|
|
18
|
+
const product = await queryOneEntity<
|
|
19
|
+
Product,
|
|
20
|
+
ProductBoolExp,
|
|
21
|
+
ProductOrderBy,
|
|
22
|
+
ProductDistinctExp
|
|
23
|
+
>(
|
|
24
|
+
newQueryProductOptions(imageSize).setQueryArgs({
|
|
25
|
+
where: {
|
|
26
|
+
slug: {
|
|
27
|
+
_eq: slug,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
envVariables
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
if (!product) {
|
|
35
|
+
return product;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const tProduct = productToViewModel(product)!;
|
|
8
39
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
40
|
+
if (product?.relatedSlugs?.length) {
|
|
41
|
+
const result = await queryEntityList<
|
|
42
|
+
Product,
|
|
43
|
+
ProductBoolExp,
|
|
44
|
+
ProductOrderBy,
|
|
45
|
+
ProductDistinctExp
|
|
46
|
+
>(
|
|
47
|
+
newQueryProductOptions(imageSize).setQueryArgs({
|
|
12
48
|
where: {
|
|
13
49
|
slug: {
|
|
14
|
-
|
|
50
|
+
_in: product?.relatedSlugs,
|
|
15
51
|
},
|
|
16
52
|
},
|
|
17
53
|
}),
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
54
|
+
envVariables
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
tProduct.related = result?.items?.map((pro) => productToViewModel(pro)) as
|
|
58
|
+
| TProduct[]
|
|
59
|
+
| undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return tProduct;
|
|
21
63
|
}
|
|
@@ -21,13 +21,7 @@ export async function queryOneTheme(envVariables: EnvVariables) {
|
|
|
21
21
|
ThemeDistinctExp
|
|
22
22
|
>(
|
|
23
23
|
new ThemeQueryOptions(
|
|
24
|
-
[
|
|
25
|
-
ThemeFields.id,
|
|
26
|
-
ThemeFields.name,
|
|
27
|
-
ThemeFields.css,
|
|
28
|
-
ThemeFields.settings,
|
|
29
|
-
ThemeFields.tailwindConfig,
|
|
30
|
-
],
|
|
24
|
+
[ThemeFields.id, ThemeFields.name, ThemeFields.settings],
|
|
31
25
|
{
|
|
32
26
|
where: {
|
|
33
27
|
lang: {
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AttachmentOnProduct,
|
|
3
3
|
Media,
|
|
4
|
-
MediaOnProduct,
|
|
5
4
|
Post,
|
|
6
5
|
PostCategory,
|
|
7
6
|
Product,
|
|
8
7
|
ProductCategory,
|
|
9
|
-
ProductRelatedPivot,
|
|
10
8
|
User,
|
|
11
9
|
WebsiteSettings,
|
|
12
10
|
} from "@rxdrag/rxcms-models";
|
|
@@ -116,23 +114,9 @@ export function productToViewModel(product?: Product): TProduct | undefined {
|
|
|
116
114
|
attachments:
|
|
117
115
|
product?.attachmentPivots &&
|
|
118
116
|
attachmentsToViewModel(product?.attachmentPivots),
|
|
119
|
-
related: relatedPovitToViewModel(product?.relatedPivot),
|
|
120
117
|
};
|
|
121
118
|
}
|
|
122
119
|
|
|
123
|
-
export function relatedPovitToViewModel(
|
|
124
|
-
related?: ProductRelatedPivot[]
|
|
125
|
-
): TProduct[] | undefined {
|
|
126
|
-
if (!related) {
|
|
127
|
-
return undefined;
|
|
128
|
-
}
|
|
129
|
-
return related.map((relatedPivot) => {
|
|
130
|
-
return productToViewModel({
|
|
131
|
-
...relatedPivot.target,
|
|
132
|
-
seqValue: relatedPivot.seqValue,
|
|
133
|
-
})!;
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
120
|
|
|
137
121
|
export function productListToViewModel(
|
|
138
122
|
products?: ListResult<Product>
|
package/src/lib/utils.ts
CHANGED
|
@@ -31,11 +31,15 @@ export function productsPagination(options: {
|
|
|
31
31
|
});
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export function productBreadcrumbs(
|
|
34
|
+
export function productBreadcrumbs(
|
|
35
|
+
product?: TProduct,
|
|
36
|
+
homeTitle: string = "Home",
|
|
37
|
+
productsTitle: string = "Products"
|
|
38
|
+
) {
|
|
35
39
|
// 生成面包屑
|
|
36
40
|
const breadcrumbs: TBreadcrumbItem[] = [
|
|
37
|
-
{ title:
|
|
38
|
-
{ title:
|
|
41
|
+
{ title: homeTitle, href: "/" },
|
|
42
|
+
{ title: productsTitle, href: "/products/page/1" },
|
|
39
43
|
];
|
|
40
44
|
|
|
41
45
|
const category = product?.category;
|
|
@@ -51,11 +55,15 @@ export function productBreadcrumbs(product?: TProduct) {
|
|
|
51
55
|
return breadcrumbs;
|
|
52
56
|
}
|
|
53
57
|
|
|
54
|
-
export function productListBreadcrumbs(
|
|
58
|
+
export function productListBreadcrumbs(
|
|
59
|
+
category?: TProductCategory | null,
|
|
60
|
+
homeTitle: string = "Home",
|
|
61
|
+
productsTitle: string = "Products"
|
|
62
|
+
) {
|
|
55
63
|
// 生成面包屑
|
|
56
64
|
const breadcrumbs: TBreadcrumbItem[] = [
|
|
57
|
-
{ title:
|
|
58
|
-
{ title:
|
|
65
|
+
{ title: homeTitle, href: "/" },
|
|
66
|
+
{ title: productsTitle, href: "/products/page/1" },
|
|
59
67
|
];
|
|
60
68
|
if (category?.name) {
|
|
61
69
|
breadcrumbs.push({
|
|
@@ -65,11 +73,15 @@ export function productListBreadcrumbs(category?: TProductCategory | null) {
|
|
|
65
73
|
return breadcrumbs;
|
|
66
74
|
}
|
|
67
75
|
|
|
68
|
-
export function postBreadcrumbs(
|
|
76
|
+
export function postBreadcrumbs(
|
|
77
|
+
post: TPost | undefined,
|
|
78
|
+
homeTitle: string = "Home",
|
|
79
|
+
postsTitle: string = "Posts"
|
|
80
|
+
) {
|
|
69
81
|
// 生成面包屑
|
|
70
82
|
const breadcrumbs: TBreadcrumbItem[] = [
|
|
71
|
-
{ title:
|
|
72
|
-
{ title:
|
|
83
|
+
{ title: homeTitle, href: "/" },
|
|
84
|
+
{ title: postsTitle, href: "/posts/page/1" },
|
|
73
85
|
];
|
|
74
86
|
|
|
75
87
|
const category = post?.category;
|
|
@@ -85,11 +97,15 @@ export function postBreadcrumbs(post?: TPost) {
|
|
|
85
97
|
return breadcrumbs;
|
|
86
98
|
}
|
|
87
99
|
|
|
88
|
-
export function postListBreadcrumbs(
|
|
100
|
+
export function postListBreadcrumbs(
|
|
101
|
+
category?: TPostCategory | null,
|
|
102
|
+
homeTitle: string = "Home",
|
|
103
|
+
postsTitle: string = "Posts"
|
|
104
|
+
) {
|
|
89
105
|
// 生成面包屑
|
|
90
106
|
const breadcrumbs: TBreadcrumbItem[] = [
|
|
91
|
-
{ title:
|
|
92
|
-
{ title:
|
|
107
|
+
{ title: homeTitle, href: "/" },
|
|
108
|
+
{ title: postsTitle, href: "/posts/page/1" },
|
|
93
109
|
];
|
|
94
110
|
if (category?.name) {
|
|
95
111
|
breadcrumbs.push({
|
|
@@ -99,10 +115,10 @@ export function postListBreadcrumbs(category?: TPostCategory) {
|
|
|
99
115
|
return breadcrumbs;
|
|
100
116
|
}
|
|
101
117
|
|
|
102
|
-
export function pageBreadcrumbs(title: string) {
|
|
118
|
+
export function pageBreadcrumbs(title: string, homeTitle: string = "Home") {
|
|
103
119
|
// 生成面包屑
|
|
104
120
|
const breadcrumbs: TBreadcrumbItem[] = [
|
|
105
|
-
{ title:
|
|
121
|
+
{ title: homeTitle, href: "/" },
|
|
106
122
|
{ title },
|
|
107
123
|
];
|
|
108
124
|
return breadcrumbs;
|
package/src/motion/consts.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AnchorOffsets,
|
|
3
3
|
AosAnimationConfig,
|
|
4
|
-
|
|
4
|
+
OpenableAnimationConfig,
|
|
5
5
|
AnimationConfig,
|
|
6
6
|
} from "./types";
|
|
7
7
|
|
|
@@ -17,7 +17,7 @@ export const DATA_MOTION_TAP = "data-motion-tap";
|
|
|
17
17
|
//入视图
|
|
18
18
|
export const DATA_MOTION_INVIEW = "data-motion-inview";
|
|
19
19
|
//弹层动画,有动作的组件联动
|
|
20
|
-
export const
|
|
20
|
+
export const DATA_MOTION_OPENABLE = "data-motion-openable";
|
|
21
21
|
//数字动画
|
|
22
22
|
export const DATA_MOTION_NUMBER = "data-motion-number";
|
|
23
23
|
export const DATA_MOTION_NUMBER_ONCE = "data-motion-number-once";
|
|
@@ -340,7 +340,7 @@ export const AOS_ANIMATIONS: Record<string, AosAnimationConfig | undefined> = {
|
|
|
340
340
|
|
|
341
341
|
export const POPUP_ANIMATIONS: Record<
|
|
342
342
|
string,
|
|
343
|
-
|
|
343
|
+
OpenableAnimationConfig | undefined
|
|
344
344
|
> = {
|
|
345
345
|
// 缩放效果
|
|
346
346
|
scale: {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { merge } from "lodash-es";
|
|
2
|
-
import {
|
|
2
|
+
import { OpenableAnimationConfig } from "./types";
|
|
3
3
|
import { POPUP_ANIMATIONS } from "./consts";
|
|
4
4
|
|
|
5
5
|
export function normalizePopupAnimation(
|
|
6
|
-
motion?:
|
|
6
|
+
motion?: OpenableAnimationConfig | string
|
|
7
7
|
) {
|
|
8
8
|
let presetKey: string | undefined;
|
|
9
|
-
let normalMotion:
|
|
9
|
+
let normalMotion: OpenableAnimationConfig | undefined;
|
|
10
10
|
if (typeof motion === "string") {
|
|
11
11
|
presetKey = motion;
|
|
12
12
|
} else {
|
package/src/motion/types.ts
CHANGED
|
@@ -122,7 +122,7 @@ export type HoverAnimationConfig = AnimationConfig & {
|
|
|
122
122
|
exit?: AnimationConfig;
|
|
123
123
|
};
|
|
124
124
|
|
|
125
|
-
export type
|
|
125
|
+
export type OpenableAnimationConfig = AnimationConfig & {
|
|
126
126
|
// 初始状态设置 (gsap.set) - 立即应用,不产生动画
|
|
127
127
|
initial?: AnimationStyles;
|
|
128
128
|
// 打开时的动画
|