@rxdrag/website-lib-core 0.0.20 → 0.0.22
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/link-client.ts +3 -4
- package/src/controller/PageLoader.ts +7 -6
- package/src/entify/Entify.ts +5 -5
- package/src/entify/IEntify.ts +3 -3
- package/src/entify/lib/fulltextSearch.ts +61 -0
- package/src/entify/lib/index.ts +1 -1
- package/src/entify/lib/queryLatestPosts.ts +3 -2
- package/src/entify/lib/queryProducts.ts +40 -34
- package/src/react/components/ContactForm/index.tsx +35 -8
- package/src/react/components/Medias/index.tsx +11 -3
- package/src/react/components/SearchInput.tsx +0 -15
- package/src/entify/lib/searchProducts.ts +0 -77
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rxdrag/website-lib-core",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.22",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.ts"
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"eslint": "^7.32.0",
|
|
26
26
|
"typescript": "^5",
|
|
27
27
|
"@rxdrag/entify-hooks": "0.2.43",
|
|
28
|
-
"@rxdrag/
|
|
28
|
+
"@rxdrag/eslint-config-custom": "0.2.12",
|
|
29
29
|
"@rxdrag/slate-preview": "1.2.57",
|
|
30
|
-
"@rxdrag/
|
|
30
|
+
"@rxdrag/tsconfig": "0.2.0"
|
|
31
31
|
},
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"clsx": "^2.1.0",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"lodash-es": "^4.17.21",
|
|
36
36
|
"react": "^18.2.0",
|
|
37
37
|
"react-dom": "^18.2.0",
|
|
38
|
-
"@rxdrag/rxcms-models": "0.3.
|
|
38
|
+
"@rxdrag/rxcms-models": "0.3.51"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"astro": "^4.0.0 || ^5.0.0"
|
|
@@ -10,12 +10,11 @@ export const initLinks = () => {
|
|
|
10
10
|
links.forEach((anchorLink) => {
|
|
11
11
|
// 从链接URL中提取路径部分
|
|
12
12
|
try {
|
|
13
|
-
const linkUrl = new URL(anchorLink.href);
|
|
13
|
+
const linkUrl = anchorLink.href ? new URL(anchorLink.href) : null;
|
|
14
14
|
const linkPath =
|
|
15
15
|
anchorLink.dataset.activedPath === "true"
|
|
16
|
-
? linkUrl
|
|
16
|
+
? linkUrl?.pathname
|
|
17
17
|
: anchorLink.dataset.activedPath;
|
|
18
|
-
|
|
19
18
|
// 检查当前路径是否与链接路径匹配或是其子路径
|
|
20
19
|
if (
|
|
21
20
|
currentPath === linkPath ||
|
|
@@ -30,4 +29,4 @@ export const initLinks = () => {
|
|
|
30
29
|
console.warn("Invalid URL:", e, anchorLink);
|
|
31
30
|
}
|
|
32
31
|
});
|
|
33
|
-
};
|
|
32
|
+
};
|
|
@@ -66,14 +66,15 @@ export class PageLoader implements IPageLoader {
|
|
|
66
66
|
|
|
67
67
|
try {
|
|
68
68
|
// 使用标志来确保回调只执行一次
|
|
69
|
-
let hasExecuted = false;
|
|
69
|
+
//let hasExecuted = false;
|
|
70
70
|
|
|
71
71
|
// 主事件处理函数,调用所有注册的回调
|
|
72
72
|
const handleEvent = () => {
|
|
73
|
+
console.log("===>页面转场事件触发,执行回调");
|
|
73
74
|
// 如果已经执行过,则不再执行
|
|
74
|
-
if (hasExecuted) return;
|
|
75
|
+
//if (hasExecuted) return;
|
|
75
76
|
|
|
76
|
-
hasExecuted = true;
|
|
77
|
+
//hasExecuted = true;
|
|
77
78
|
|
|
78
79
|
// 执行所有回调
|
|
79
80
|
this.callbacks.forEach((callback) => {
|
|
@@ -85,9 +86,9 @@ export class PageLoader implements IPageLoader {
|
|
|
85
86
|
});
|
|
86
87
|
|
|
87
88
|
// 重置执行标志,允许下一次页面转场时再次执行
|
|
88
|
-
setTimeout(() => {
|
|
89
|
-
|
|
90
|
-
}, 100);
|
|
89
|
+
// setTimeout(() => {
|
|
90
|
+
// hasExecuted = false;
|
|
91
|
+
// }, 100);
|
|
91
92
|
};
|
|
92
93
|
|
|
93
94
|
// 只监听一个事件,优先使用 astro:page-load
|
package/src/entify/Entify.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
queryProductCategories,
|
|
17
17
|
queryProducts,
|
|
18
18
|
queryUserPosts,
|
|
19
|
-
|
|
19
|
+
fulltextSearch,
|
|
20
20
|
} from "./lib";
|
|
21
21
|
import { IQueryOptions } from "@rxdrag/entify-hooks";
|
|
22
22
|
import { queryAllProducts } from "./lib/queryAllProducts";
|
|
@@ -72,8 +72,8 @@ export class Entify implements IEntify {
|
|
|
72
72
|
return await queryFeaturedProducts(count, this.envVariables);
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
public async getLatestPosts(count?: number) {
|
|
76
|
-
return await queryLatestPosts(count, this.envVariables);
|
|
75
|
+
public async getLatestPosts(count?: number, coverSize?: TSize) {
|
|
76
|
+
return await queryLatestPosts(count, coverSize, this.envVariables);
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
public async getHomePage(): Promise<Page | undefined> {
|
|
@@ -371,8 +371,8 @@ export class Entify implements IEntify {
|
|
|
371
371
|
return (await queryUserPosts({ userId }, this.envVariables))?.items;
|
|
372
372
|
}
|
|
373
373
|
|
|
374
|
-
public async
|
|
375
|
-
return await
|
|
374
|
+
public async fulltextSearch(keyword: string, imageSize: TSize | undefined) {
|
|
375
|
+
return await fulltextSearch(keyword, imageSize,this.envVariables);
|
|
376
376
|
}
|
|
377
377
|
|
|
378
378
|
public async getUserPaths() {
|
package/src/entify/IEntify.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
TProductCategory,
|
|
9
9
|
TUser,
|
|
10
10
|
} from "./view-model";
|
|
11
|
-
import { Lang, Page, PageType, Theme, Website } from "@rxdrag/rxcms-models";
|
|
11
|
+
import { Lang, Page, PageType, SearchIndex, Theme, Website } from "@rxdrag/rxcms-models";
|
|
12
12
|
|
|
13
13
|
export type PostsOptions = {
|
|
14
14
|
category?: string;
|
|
@@ -43,7 +43,7 @@ export interface IEntify {
|
|
|
43
43
|
|
|
44
44
|
getFeaturedProducts(count?: number): Promise<TProduct[] | undefined>;
|
|
45
45
|
|
|
46
|
-
getLatestPosts(count?: number): Promise<TPost[] | undefined>;
|
|
46
|
+
getLatestPosts(count?: number, coverSize?: TSize): Promise<TPost[] | undefined>;
|
|
47
47
|
|
|
48
48
|
getPosts(options: PostsOptions): Promise<TPost[] | undefined>;
|
|
49
49
|
|
|
@@ -123,7 +123,7 @@ export interface IEntify {
|
|
|
123
123
|
|
|
124
124
|
getUserPosts(userId: string): Promise<TPost[] | undefined>;
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
fulltextSearch(keyword: string, imageSize: TSize | undefined): Promise<ListResult<SearchIndex> | undefined>;
|
|
127
127
|
|
|
128
128
|
getUserPaths(): Promise<unknown>;
|
|
129
129
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PublishableStatus,
|
|
3
|
+
SearchIndex,
|
|
4
|
+
SearchIndexBoolExp,
|
|
5
|
+
SearchIndexOrderBy,
|
|
6
|
+
SearchIndexDistinctExp,
|
|
7
|
+
SearchIndexQueryOptions,
|
|
8
|
+
SearchIndexFields,
|
|
9
|
+
MediaQueryOptions,
|
|
10
|
+
} from "@rxdrag/rxcms-models";
|
|
11
|
+
import { queryEntityList } from "./queryEntityList";
|
|
12
|
+
import { ListResult } from "@rxdrag/entify-hooks";
|
|
13
|
+
import { EnvVariables, TSize } from "../types";
|
|
14
|
+
|
|
15
|
+
export async function fulltextSearch(
|
|
16
|
+
keyword: string,
|
|
17
|
+
imageSize: TSize | undefined,
|
|
18
|
+
envVariables: EnvVariables
|
|
19
|
+
) {
|
|
20
|
+
|
|
21
|
+
const queryOptions = new SearchIndexQueryOptions(
|
|
22
|
+
[
|
|
23
|
+
SearchIndexFields.id,
|
|
24
|
+
SearchIndexFields.title,
|
|
25
|
+
SearchIndexFields.summary,
|
|
26
|
+
SearchIndexFields.sourceId,
|
|
27
|
+
SearchIndexFields.sourceType,
|
|
28
|
+
SearchIndexFields.sourceLang,
|
|
29
|
+
SearchIndexFields.sourceSlug,
|
|
30
|
+
],
|
|
31
|
+
{
|
|
32
|
+
limit: 100,
|
|
33
|
+
where: {
|
|
34
|
+
sourceLang: {
|
|
35
|
+
_eq: envVariables.language,
|
|
36
|
+
},
|
|
37
|
+
[SearchIndexFields.sourceStatus]: {
|
|
38
|
+
_eq: PublishableStatus.published,
|
|
39
|
+
},
|
|
40
|
+
content: {
|
|
41
|
+
_match: keyword,
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
).media(new MediaQueryOptions().file([
|
|
46
|
+
"thumbnail(width:400, height:320)",
|
|
47
|
+
"url",
|
|
48
|
+
imageSize
|
|
49
|
+
? `resize(width:${imageSize.width}, height:${imageSize.height})`
|
|
50
|
+
: "resize(width:500, height:400)",
|
|
51
|
+
])).setNoQuery(!keyword);
|
|
52
|
+
|
|
53
|
+
const result = await queryEntityList<
|
|
54
|
+
SearchIndex,
|
|
55
|
+
SearchIndexBoolExp,
|
|
56
|
+
SearchIndexOrderBy,
|
|
57
|
+
SearchIndexDistinctExp
|
|
58
|
+
>(queryOptions, envVariables);
|
|
59
|
+
|
|
60
|
+
return result as ListResult<SearchIndex> | undefined;
|
|
61
|
+
}
|
package/src/entify/lib/index.ts
CHANGED
|
@@ -12,11 +12,12 @@ import {
|
|
|
12
12
|
PublishableStatus,
|
|
13
13
|
} from "@rxdrag/rxcms-models";
|
|
14
14
|
import { queryEntityList } from "./queryEntityList";
|
|
15
|
-
import { EnvVariables } from "../types";
|
|
15
|
+
import { EnvVariables, TSize } from "../types";
|
|
16
16
|
import { TPost } from "../view-model";
|
|
17
17
|
|
|
18
18
|
export async function queryLatestPosts(
|
|
19
19
|
count: number = 2,
|
|
20
|
+
coverSize: TSize | undefined,
|
|
20
21
|
envVariables: EnvVariables
|
|
21
22
|
) {
|
|
22
23
|
const result = await queryEntityList<
|
|
@@ -56,7 +57,7 @@ export async function queryLatestPosts(
|
|
|
56
57
|
.cover(
|
|
57
58
|
new MediaQueryOptions().file([
|
|
58
59
|
"thumbnail",
|
|
59
|
-
|
|
60
|
+
`resize(width:${coverSize?.width || 480}, height:${coverSize?.height || 180})`,
|
|
60
61
|
])
|
|
61
62
|
)
|
|
62
63
|
.author(
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Product,
|
|
3
|
+
ProductBoolExp,
|
|
4
|
+
ProductOrderBy,
|
|
5
|
+
ProductDistinctExp,
|
|
6
|
+
ProductFields,
|
|
7
|
+
ProductQueryOptions,
|
|
8
|
+
PublishableStatus,
|
|
9
|
+
ProductAssciations,
|
|
10
|
+
} from "@rxdrag/rxcms-models";
|
|
2
11
|
import { ListConditions } from "./queryPosts";
|
|
3
12
|
import { queryEntityList } from "./queryEntityList";
|
|
4
13
|
import { newQueryProductsMediaOptions } from "./newQueryProductsMediaOptions";
|
|
@@ -7,22 +16,22 @@ import { EnvVariables, TSize } from "../types";
|
|
|
7
16
|
import { TProduct } from "../view-model";
|
|
8
17
|
|
|
9
18
|
export async function queryProducts(
|
|
10
|
-
conditions: ListConditions,
|
|
11
|
-
imageSize: TSize | undefined,
|
|
19
|
+
conditions: ListConditions,
|
|
20
|
+
imageSize: TSize | undefined,
|
|
12
21
|
envVariables: EnvVariables,
|
|
13
22
|
selectFields?: (keyof Product)[]
|
|
14
23
|
) {
|
|
15
24
|
const { category: categorySlug, page = 1, pageSize = 10 } = conditions;
|
|
16
25
|
|
|
17
|
-
let where = {}
|
|
26
|
+
let where = {};
|
|
18
27
|
if (categorySlug) {
|
|
19
28
|
where = {
|
|
20
29
|
[ProductAssciations.category]: {
|
|
21
30
|
slug: {
|
|
22
|
-
|
|
23
|
-
}
|
|
31
|
+
_eq: categorySlug,
|
|
32
|
+
},
|
|
24
33
|
},
|
|
25
|
-
}
|
|
34
|
+
};
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
// 默认查询字段
|
|
@@ -37,38 +46,35 @@ export async function queryProducts(
|
|
|
37
46
|
// 使用指定的字段或默认字段
|
|
38
47
|
const fields = selectFields || defaultFields;
|
|
39
48
|
|
|
40
|
-
const queryOptions = new ProductQueryOptions(
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
abbr: {
|
|
51
|
-
_eq: envVariables.language,
|
|
52
|
-
},
|
|
49
|
+
const queryOptions = new ProductQueryOptions(fields, {
|
|
50
|
+
offset: (page - 1) * pageSize,
|
|
51
|
+
limit: pageSize,
|
|
52
|
+
where: {
|
|
53
|
+
[ProductFields.status]: {
|
|
54
|
+
_eq: PublishableStatus.published,
|
|
55
|
+
},
|
|
56
|
+
lang: {
|
|
57
|
+
abbr: {
|
|
58
|
+
_eq: envVariables.language,
|
|
53
59
|
},
|
|
54
|
-
...where,
|
|
55
60
|
},
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
+
...where,
|
|
62
|
+
},
|
|
63
|
+
orderBy: [
|
|
64
|
+
{ [ProductFields.seqValue]: "asc", [ProductFields.updatedAt]: "desc" },
|
|
65
|
+
],
|
|
66
|
+
});
|
|
61
67
|
|
|
62
68
|
// 只有在不指定字段或需要查询媒体时才添加媒体查询
|
|
63
|
-
if (!selectFields || !selectFields.includes(
|
|
64
|
-
queryOptions.mediaPivots(
|
|
65
|
-
newQueryProductsMediaOptions(imageSize)
|
|
66
|
-
);
|
|
69
|
+
if (!selectFields || !selectFields.includes("slug" as keyof Product)) {
|
|
70
|
+
queryOptions.mediaPivots(newQueryProductsMediaOptions(imageSize));
|
|
67
71
|
}
|
|
68
72
|
|
|
69
|
-
const result = await queryEntityList<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
const result = await queryEntityList<
|
|
74
|
+
Product,
|
|
75
|
+
ProductBoolExp,
|
|
76
|
+
ProductOrderBy,
|
|
77
|
+
ProductDistinctExp
|
|
78
|
+
>(queryOptions, envVariables);
|
|
73
79
|
return result as ListResult<TProduct> | undefined;
|
|
74
80
|
}
|
|
@@ -76,6 +76,8 @@ export interface QuoteRequest {
|
|
|
76
76
|
company?: string;
|
|
77
77
|
message?: string;
|
|
78
78
|
fromCta?: string;
|
|
79
|
+
// 电话或者whatsapp
|
|
80
|
+
mobile?: string;
|
|
79
81
|
// 蜜罐字段,用于检测机器人
|
|
80
82
|
phone: string;
|
|
81
83
|
// 一个加密字段,用于防机器人,点击时附加一个加密的字符串
|
|
@@ -91,12 +93,17 @@ export type ContactFormProps = {
|
|
|
91
93
|
submitAlign?: "left" | "center" | "right";
|
|
92
94
|
actionUrl?: string;
|
|
93
95
|
formSalt: string;
|
|
96
|
+
classNames?: {
|
|
97
|
+
submit?: string;
|
|
98
|
+
container?: string;
|
|
99
|
+
};
|
|
94
100
|
labels?: {
|
|
95
101
|
name?: string;
|
|
96
102
|
email?: string;
|
|
97
103
|
company?: string;
|
|
98
104
|
message?: string;
|
|
99
105
|
submit?: string;
|
|
106
|
+
mobile?: string;
|
|
100
107
|
};
|
|
101
108
|
};
|
|
102
109
|
|
|
@@ -107,6 +114,7 @@ export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
|
107
114
|
actionUrl = "/api/ask-for-quote",
|
|
108
115
|
formSalt,
|
|
109
116
|
labels = {},
|
|
117
|
+
classNames = {},
|
|
110
118
|
} = props;
|
|
111
119
|
const [formData, setFormData] = useState<QuoteRequest>({
|
|
112
120
|
name: "",
|
|
@@ -115,6 +123,8 @@ export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
|
115
123
|
message: "",
|
|
116
124
|
phone: "", // 初始化蜜罐字段
|
|
117
125
|
});
|
|
126
|
+
const submitClassName = classNames.submit || "btn-primary";
|
|
127
|
+
const containerClassName = classNames.container || "gap-y-6";
|
|
118
128
|
// 错误状态
|
|
119
129
|
const [errors, setErrors] = useState<FormErrors>({});
|
|
120
130
|
const [submitting, setSubmitting] = useState(false);
|
|
@@ -236,8 +246,21 @@ export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
|
236
246
|
return (
|
|
237
247
|
<div
|
|
238
248
|
ref={ref}
|
|
239
|
-
className=
|
|
249
|
+
className={clsx(
|
|
250
|
+
"py-4 grid max-w-2xl grid-cols-1 gap-x-6 sm:grid-cols-2",
|
|
251
|
+
containerClassName
|
|
252
|
+
)}
|
|
240
253
|
>
|
|
254
|
+
<Input
|
|
255
|
+
className="sm:col-span-1"
|
|
256
|
+
inputClassName="mt-2 block w-full rounded-md outline-none border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6"
|
|
257
|
+
label={labels?.name || "Your Name"}
|
|
258
|
+
labelClassName="block text-sm font-medium leading-6 text-gray-900"
|
|
259
|
+
name="name"
|
|
260
|
+
value={formData.name}
|
|
261
|
+
onChange={handleChange}
|
|
262
|
+
error={errors.name}
|
|
263
|
+
/>
|
|
241
264
|
<Input
|
|
242
265
|
className="sm:col-span-1"
|
|
243
266
|
inputClassName="mt-2 block w-full rounded-md outline-none border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6"
|
|
@@ -254,17 +277,18 @@ export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
|
254
277
|
<Input
|
|
255
278
|
className="sm:col-span-1"
|
|
256
279
|
inputClassName="mt-2 block w-full rounded-md outline-none border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6"
|
|
257
|
-
label={
|
|
280
|
+
label={labels?.mobile || "Your tel"}
|
|
258
281
|
labelClassName="block text-sm font-medium leading-6 text-gray-900"
|
|
259
|
-
name="
|
|
260
|
-
|
|
282
|
+
name="mobile"
|
|
283
|
+
required={true}
|
|
284
|
+
autoFocus={true}
|
|
285
|
+
value={formData.mobile}
|
|
261
286
|
onChange={handleChange}
|
|
262
|
-
error={errors.name}
|
|
263
287
|
/>
|
|
264
288
|
<Input
|
|
265
|
-
className="col-span-
|
|
289
|
+
className="sm:col-span-1"
|
|
266
290
|
inputClassName="mt-2 block w-full rounded-md outline-none border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-sky-600 sm:text-sm sm:leading-6"
|
|
267
|
-
label={
|
|
291
|
+
label={labels?.company || "Company"}
|
|
268
292
|
labelClassName="block text-sm font-medium leading-6 text-gray-900"
|
|
269
293
|
name="company"
|
|
270
294
|
value={formData.company}
|
|
@@ -309,7 +333,10 @@ export const ContactForm = forwardRef<HTMLDivElement, ContactFormProps>(
|
|
|
309
333
|
</div>
|
|
310
334
|
)}
|
|
311
335
|
<Submit
|
|
312
|
-
className=
|
|
336
|
+
className={clsx(
|
|
337
|
+
"flex gap-2 items-center relative shadow-sm btn btn-lg nowrap",
|
|
338
|
+
submitClassName
|
|
339
|
+
)}
|
|
313
340
|
title={labels?.submit || "Send Message"}
|
|
314
341
|
spinner={
|
|
315
342
|
<div className="left-8 flex items-center justify-center">
|
|
@@ -9,6 +9,11 @@ export type MediasProps = {
|
|
|
9
9
|
// Aspect ratio, format is `aspect-[width/height]`
|
|
10
10
|
aspect?: string;
|
|
11
11
|
thumbnailAspect?: string;
|
|
12
|
+
classNames?: {
|
|
13
|
+
mainArea?: string;
|
|
14
|
+
navigation?: string;
|
|
15
|
+
thumbnail?: string;
|
|
16
|
+
}
|
|
12
17
|
};
|
|
13
18
|
|
|
14
19
|
export const Medias = forwardRef<HTMLDivElement, MediasProps>((props, ref) => {
|
|
@@ -18,8 +23,10 @@ export const Medias = forwardRef<HTMLDivElement, MediasProps>((props, ref) => {
|
|
|
18
23
|
children,
|
|
19
24
|
aspect = "aspect-[1/1]",
|
|
20
25
|
thumbnailAspect = "aspect-[5/4]",
|
|
26
|
+
classNames,
|
|
21
27
|
...rest
|
|
22
28
|
} = props;
|
|
29
|
+
const { mainArea, navigation, thumbnail } = classNames || {};
|
|
23
30
|
const [selectedId, setSelectedId] = useState<string | undefined | null>(
|
|
24
31
|
value?.externalVideoUrl ? "video" : value?.medias?.[0]?.id || ""
|
|
25
32
|
);
|
|
@@ -136,7 +143,7 @@ export const Medias = forwardRef<HTMLDivElement, MediasProps>((props, ref) => {
|
|
|
136
143
|
<div ref={ref} className={clsx("flex flex-col", className)} {...rest}>
|
|
137
144
|
{children}
|
|
138
145
|
{/* Main display area */}
|
|
139
|
-
<div className={clsx("relative group")}>
|
|
146
|
+
<div className={clsx("relative group", mainArea)}>
|
|
140
147
|
{canPrevious && (
|
|
141
148
|
<button
|
|
142
149
|
onClick={handlePrevious}
|
|
@@ -211,7 +218,7 @@ export const Medias = forwardRef<HTMLDivElement, MediasProps>((props, ref) => {
|
|
|
211
218
|
</div>
|
|
212
219
|
|
|
213
220
|
{/* Thumbnail navigation */}
|
|
214
|
-
<div className="relative mt-4">
|
|
221
|
+
<div className={clsx("relative mt-4", navigation)}>
|
|
215
222
|
<div className="flex items-stretch gap-2">
|
|
216
223
|
{totalItems > 6 && (
|
|
217
224
|
<button
|
|
@@ -222,7 +229,8 @@ export const Medias = forwardRef<HTMLDivElement, MediasProps>((props, ref) => {
|
|
|
222
229
|
"transition-colors duration-200 rounded-l-md",
|
|
223
230
|
!canPrevious
|
|
224
231
|
? "bg-gray-100 text-gray-400 cursor-not-allowed"
|
|
225
|
-
: "bg-gray-200 hover:bg-gray-300 text-gray-700"
|
|
232
|
+
: "bg-gray-200 hover:bg-gray-300 text-gray-700",
|
|
233
|
+
thumbnail,
|
|
226
234
|
)}
|
|
227
235
|
aria-label="Previous"
|
|
228
236
|
>
|
|
@@ -8,25 +8,10 @@ export const SearchInput = forwardRef<HTMLInputElement, SearchProps>(
|
|
|
8
8
|
const { children, ...rest } = props;
|
|
9
9
|
const [keyword, setKeyword] = useState<string>();
|
|
10
10
|
|
|
11
|
-
// const navigate = useNavigate();
|
|
12
|
-
// const [, setOpen] = useXModalState();
|
|
13
|
-
|
|
14
|
-
const handleKeyEnter = (event: React.KeyboardEvent<HTMLElement>) => {
|
|
15
|
-
if (event.key !== "Enter" || !keyword) {
|
|
16
|
-
return;
|
|
17
|
-
}
|
|
18
|
-
// setOpen?.(false);
|
|
19
|
-
const encodedKeyword = encodeURIComponent(keyword || "");
|
|
20
|
-
if (encodedKeyword) {
|
|
21
|
-
//navigate(`/search?keyword=${encodedKeyword}`);
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
|
|
25
11
|
return (
|
|
26
12
|
<input
|
|
27
13
|
ref={ref}
|
|
28
14
|
name="q"
|
|
29
|
-
onKeyDown={handleKeyEnter}
|
|
30
15
|
value={keyword}
|
|
31
16
|
onChange={(e) => setKeyword(e.target.value)}
|
|
32
17
|
{...rest}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Product,
|
|
3
|
-
ProductBoolExp,
|
|
4
|
-
ProductOrderBy,
|
|
5
|
-
ProductDistinctExp,
|
|
6
|
-
ProductFields,
|
|
7
|
-
ProductQueryOptions,
|
|
8
|
-
PublishableStatus,
|
|
9
|
-
} from "@rxdrag/rxcms-models";
|
|
10
|
-
import { queryEntityList } from "./queryEntityList";
|
|
11
|
-
import { newQueryProductsMediaOptions } from "./newQueryProductsMediaOptions";
|
|
12
|
-
import { ListResult } from "@rxdrag/entify-hooks";
|
|
13
|
-
import { EnvVariables } from "../types";
|
|
14
|
-
import { TProduct } from "../view-model";
|
|
15
|
-
|
|
16
|
-
export async function searchProducts(
|
|
17
|
-
keyword: string,
|
|
18
|
-
envVariables: EnvVariables
|
|
19
|
-
) {
|
|
20
|
-
const keyExp = keyword
|
|
21
|
-
? {
|
|
22
|
-
_or: [
|
|
23
|
-
{
|
|
24
|
-
title: {
|
|
25
|
-
_like: `%${keyword}%`,
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
[ProductFields.description]: {
|
|
30
|
-
_like: `%${keyword}%`,
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
],
|
|
34
|
-
}
|
|
35
|
-
: undefined;
|
|
36
|
-
|
|
37
|
-
const keyArray = keyExp ? [keyExp] : [];
|
|
38
|
-
|
|
39
|
-
const queryOptions = new ProductQueryOptions(
|
|
40
|
-
[
|
|
41
|
-
ProductFields.id,
|
|
42
|
-
ProductFields.slug,
|
|
43
|
-
ProductFields.title,
|
|
44
|
-
ProductFields.shortTitle,
|
|
45
|
-
ProductFields.description,
|
|
46
|
-
],
|
|
47
|
-
{
|
|
48
|
-
limit: 100,
|
|
49
|
-
where: {
|
|
50
|
-
_and: [
|
|
51
|
-
{
|
|
52
|
-
lang: {
|
|
53
|
-
abbr: {
|
|
54
|
-
_eq: envVariables.language,
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
[ProductFields.status]: {
|
|
60
|
-
_eq: PublishableStatus.published,
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
...keyArray,
|
|
64
|
-
],
|
|
65
|
-
},
|
|
66
|
-
orderBy: [{ [ProductFields.seqValue]: "asc" }],
|
|
67
|
-
}
|
|
68
|
-
).mediaPivots(newQueryProductsMediaOptions());
|
|
69
|
-
|
|
70
|
-
const result = await queryEntityList<
|
|
71
|
-
Product,
|
|
72
|
-
ProductBoolExp,
|
|
73
|
-
ProductOrderBy,
|
|
74
|
-
ProductDistinctExp
|
|
75
|
-
>(queryOptions, envVariables);
|
|
76
|
-
return result as ListResult<TProduct> | undefined;
|
|
77
|
-
}
|