@stephenchenorg/astro 5.0.1 → 6.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.
- package/dist/api/index.d.ts +76 -3
- package/dist/api/index.js +140 -3
- package/dist/company-setting/index.d.ts +47 -3
- package/dist/company-setting/index.js +47 -3
- package/dist/form-validator/index.d.ts +72 -6
- package/dist/form-validator/index.js +106 -5
- package/dist/image/index.d.ts +16 -4
- package/dist/image/index.js +30 -4
- package/dist/page/components/PageFieldRender.astro +3 -3
- package/dist/page/index.d.ts +101 -4
- package/dist/page/index.js +88 -4
- package/dist/pagination-astro/index.d.ts +30 -2
- package/dist/pagination-astro/index.js +37 -2
- package/dist/pagination-vue/index.d.ts +33 -2
- package/dist/pagination-vue/index.js +44 -2
- package/dist/product-variant/index.d.ts +69 -2
- package/dist/product-variant/index.js +57 -2
- package/dist/query-params/components/ProvideUrlConfig.astro +1 -2
- package/dist/query-params/index.d.ts +35 -6
- package/dist/query-params/index.js +62 -6
- package/package.json +10 -6
- package/dist/api/error.d.ts +0 -54
- package/dist/api/error.js +0 -97
- package/dist/api/errorResponse.d.ts +0 -1
- package/dist/api/errorResponse.js +0 -9
- package/dist/api/fetch.d.ts +0 -13
- package/dist/api/fetch.js +0 -49
- package/dist/company-setting/create.d.ts +0 -18
- package/dist/company-setting/create.js +0 -19
- package/dist/company-setting/fragments.d.ts +0 -1
- package/dist/company-setting/fragments.js +0 -20
- package/dist/company-setting/types.d.ts +0 -20
- package/dist/company-setting/types.js +0 -0
- package/dist/form-validator/FormValidator.d.ts +0 -12
- package/dist/form-validator/FormValidator.js +0 -47
- package/dist/form-validator/components/FormField.vue +0 -30
- package/dist/form-validator/components/FormValidatorProvider.d.ts +0 -22
- package/dist/form-validator/components/FormValidatorProvider.js +0 -24
- package/dist/form-validator/injectionKey.d.ts +0 -3
- package/dist/form-validator/injectionKey.js +0 -1
- package/dist/form-validator/types.d.ts +0 -5
- package/dist/form-validator/types.js +0 -0
- package/dist/image/fragments.d.ts +0 -3
- package/dist/image/fragments.js +0 -25
- package/dist/image/types.d.ts +0 -6
- package/dist/image/types.js +0 -0
- package/dist/page/field/fragments.d.ts +0 -5
- package/dist/page/field/fragments.js +0 -23
- package/dist/page/field/helpers.d.ts +0 -7
- package/dist/page/field/helpers.js +0 -20
- package/dist/page/field/index.d.ts +0 -2
- package/dist/page/field/index.js +0 -2
- package/dist/page/seo-meta/fragments.d.ts +0 -1
- package/dist/page/seo-meta/fragments.js +0 -14
- package/dist/page/seo-meta/helpers.d.ts +0 -7
- package/dist/page/seo-meta/helpers.js +0 -14
- package/dist/page/seo-meta/index.d.ts +0 -2
- package/dist/page/seo-meta/index.js +0 -2
- package/dist/page/types.d.ts +0 -69
- package/dist/page/types.js +0 -0
- package/dist/pagination-astro/types.d.ts +0 -5
- package/dist/pagination-astro/types.js +0 -0
- package/dist/pagination-astro/usePagination.d.ts +0 -20
- package/dist/pagination-astro/usePagination.js +0 -42
- package/dist/pagination-vue/types.d.ts +0 -5
- package/dist/pagination-vue/types.js +0 -0
- package/dist/pagination-vue/usePagination.d.ts +0 -21
- package/dist/pagination-vue/usePagination.js +0 -44
- package/dist/product-variant/ProductVariantSelector.d.ts +0 -42
- package/dist/product-variant/ProductVariantSelector.js +0 -52
- package/dist/product-variant/types.d.ts +0 -20
- package/dist/product-variant/types.js +0 -0
- package/dist/query-params/config.d.ts +0 -2
- package/dist/query-params/config.js +0 -3
- package/dist/query-params/store.d.ts +0 -2
- package/dist/query-params/store.js +0 -7
- package/dist/query-params/types.d.ts +0 -6
- package/dist/query-params/types.js +0 -0
- package/dist/query-params/url.d.ts +0 -13
- package/dist/query-params/url.js +0 -30
- package/dist/query-params/utils.d.ts +0 -2
- package/dist/query-params/utils.js +0 -21
package/dist/page/index.js
CHANGED
|
@@ -1,4 +1,88 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { gql } from "graphql-tag";
|
|
2
|
+
|
|
3
|
+
//#region src/page/field/fragments.ts
|
|
4
|
+
/**
|
|
5
|
+
* Page fields fragment requires explicit import image
|
|
6
|
+
* fields fragment `imageFields` from Image module.
|
|
7
|
+
*/
|
|
8
|
+
const pageFields = gql`
|
|
9
|
+
fragment PageFields on Page {
|
|
10
|
+
title
|
|
11
|
+
seo_title
|
|
12
|
+
seo_description
|
|
13
|
+
seo_keyword
|
|
14
|
+
seo_json_ld
|
|
15
|
+
seo_head
|
|
16
|
+
seo_body
|
|
17
|
+
og_title
|
|
18
|
+
og_description
|
|
19
|
+
og_image
|
|
20
|
+
fields {
|
|
21
|
+
key
|
|
22
|
+
content
|
|
23
|
+
type
|
|
24
|
+
image {
|
|
25
|
+
...ImageFields
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/page/field/helpers.ts
|
|
33
|
+
function isPlainTextField(field) {
|
|
34
|
+
return field.type === "text";
|
|
35
|
+
}
|
|
36
|
+
function isPlainTextareaField(field) {
|
|
37
|
+
return field.type === "textarea";
|
|
38
|
+
}
|
|
39
|
+
function isContentField(field) {
|
|
40
|
+
return field.type === "html";
|
|
41
|
+
}
|
|
42
|
+
function isImageField(field) {
|
|
43
|
+
return field.type === "image";
|
|
44
|
+
}
|
|
45
|
+
function pageTextField(fields, key) {
|
|
46
|
+
const field = fields.find((field$1) => field$1.key === key && isPlainTextField(field$1));
|
|
47
|
+
return field ? field.content : "";
|
|
48
|
+
}
|
|
49
|
+
function pageImageFieldForBackground(fields, key) {
|
|
50
|
+
const field = fields.find((field$1) => field$1.key === key && isImageField(field$1));
|
|
51
|
+
return field ? `background-image: url('${field.image.desktop}');` : "";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/page/seo-meta/fragments.ts
|
|
56
|
+
const seoMetaFields = (dummyClass) => gql(`
|
|
57
|
+
fragment DummyClassSeoMetaFields on DummyClass {
|
|
58
|
+
seo_title
|
|
59
|
+
seo_description
|
|
60
|
+
seo_keyword
|
|
61
|
+
seo_json_ld
|
|
62
|
+
seo_head
|
|
63
|
+
seo_body
|
|
64
|
+
og_title
|
|
65
|
+
og_description
|
|
66
|
+
og_image
|
|
67
|
+
}
|
|
68
|
+
`.replace(/DummyClass/g, dummyClass));
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region src/page/seo-meta/helpers.ts
|
|
72
|
+
function seoMeta(options, modelMeta) {
|
|
73
|
+
return {
|
|
74
|
+
title: modelMeta?.title || options.title,
|
|
75
|
+
seo_title: modelMeta?.seo_title || options.seo_title || null,
|
|
76
|
+
seo_description: modelMeta?.seo_description || options.seo_description || options.description || null,
|
|
77
|
+
seo_keyword: modelMeta?.seo_keyword || options.seo_keyword || null,
|
|
78
|
+
seo_json_ld: modelMeta?.seo_json_ld || options.seo_json_ld || null,
|
|
79
|
+
seo_head: modelMeta?.seo_head || options.seo_head,
|
|
80
|
+
seo_body: modelMeta?.seo_body || options.seo_body,
|
|
81
|
+
og_title: modelMeta?.og_title || options.og_title || options.title || null,
|
|
82
|
+
og_description: modelMeta?.og_description || options.og_description || options.description || null,
|
|
83
|
+
og_image: modelMeta?.og_image || options.og_image || options.image || null
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//#endregion
|
|
88
|
+
export { isContentField, isImageField, isPlainTextField, isPlainTextareaField, pageFields, pageImageFieldForBackground, pageTextField, seoMeta, seoMetaFields };
|
|
@@ -1,2 +1,30 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/pagination-astro/types.d.ts
|
|
2
|
+
interface Paginator<T> {
|
|
3
|
+
total: number;
|
|
4
|
+
per_page: number;
|
|
5
|
+
data: T[];
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/pagination-astro/usePagination.d.ts
|
|
9
|
+
declare function usePagination(options: {
|
|
10
|
+
total: number;
|
|
11
|
+
currentPage: number;
|
|
12
|
+
url: string;
|
|
13
|
+
perPage?: number;
|
|
14
|
+
visiblePages?: number;
|
|
15
|
+
}): {
|
|
16
|
+
items: number[];
|
|
17
|
+
showPagination: boolean;
|
|
18
|
+
currentPage: number;
|
|
19
|
+
canFirst: boolean;
|
|
20
|
+
canPrev: boolean;
|
|
21
|
+
canNext: boolean;
|
|
22
|
+
canLast: boolean;
|
|
23
|
+
firstUrl: string;
|
|
24
|
+
prevUrl: string;
|
|
25
|
+
nextUrl: string;
|
|
26
|
+
lastUrl: string;
|
|
27
|
+
getUrl: (page: number) => string;
|
|
28
|
+
};
|
|
29
|
+
//#endregion
|
|
30
|
+
export { Paginator, usePagination };
|
|
@@ -1,2 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/pagination-astro/usePagination.ts
|
|
2
|
+
function usePagination(options) {
|
|
3
|
+
const { total, currentPage, perPage = 12 } = options;
|
|
4
|
+
const items = [];
|
|
5
|
+
const totalPages = Math.ceil(total / perPage);
|
|
6
|
+
const visiblePages = Math.min(options.visiblePages || 5, totalPages);
|
|
7
|
+
const sideCount = Math.floor(visiblePages / 2);
|
|
8
|
+
let start = Math.max(1, currentPage - sideCount);
|
|
9
|
+
let end = Math.min(totalPages, currentPage + sideCount);
|
|
10
|
+
if (end - start + 1 < visiblePages && currentPage > 0) {
|
|
11
|
+
if (currentPage <= sideCount) end = Math.min(totalPages, start + visiblePages - 1);
|
|
12
|
+
else if (currentPage > totalPages - sideCount) start = Math.max(1, end - visiblePages + 1);
|
|
13
|
+
}
|
|
14
|
+
for (let i = start; i <= end; i++) items.push(i);
|
|
15
|
+
function getUrl(page) {
|
|
16
|
+
const url = new URL(options.url);
|
|
17
|
+
url.searchParams.set("page", String(page));
|
|
18
|
+
return url.toString();
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
items,
|
|
22
|
+
showPagination: total > perPage,
|
|
23
|
+
currentPage,
|
|
24
|
+
canFirst: currentPage > 1,
|
|
25
|
+
canPrev: currentPage > 1,
|
|
26
|
+
canNext: currentPage < totalPages,
|
|
27
|
+
canLast: currentPage < totalPages,
|
|
28
|
+
firstUrl: getUrl(1),
|
|
29
|
+
prevUrl: getUrl(currentPage - 1),
|
|
30
|
+
nextUrl: getUrl(currentPage + 1),
|
|
31
|
+
lastUrl: getUrl(totalPages),
|
|
32
|
+
getUrl
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { usePagination };
|
|
@@ -1,2 +1,33 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import * as vue27 from "vue";
|
|
2
|
+
import { MaybeRefOrGetter } from "vue";
|
|
3
|
+
|
|
4
|
+
//#region src/pagination-vue/types.d.ts
|
|
5
|
+
interface Paginator<T> {
|
|
6
|
+
total: number;
|
|
7
|
+
per_page: number;
|
|
8
|
+
data: T[];
|
|
9
|
+
}
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/pagination-vue/usePagination.d.ts
|
|
12
|
+
declare function usePagination(options: {
|
|
13
|
+
total: MaybeRefOrGetter<number>;
|
|
14
|
+
currentPage: MaybeRefOrGetter<number>;
|
|
15
|
+
url: string;
|
|
16
|
+
perPage?: MaybeRefOrGetter<number>;
|
|
17
|
+
visiblePages?: MaybeRefOrGetter<number>;
|
|
18
|
+
}): {
|
|
19
|
+
items: vue27.ComputedRef<number[]>;
|
|
20
|
+
showPagination: vue27.ComputedRef<boolean>;
|
|
21
|
+
currentPage: vue27.ComputedRef<number>;
|
|
22
|
+
canFirst: vue27.ComputedRef<boolean>;
|
|
23
|
+
canPrev: vue27.ComputedRef<boolean>;
|
|
24
|
+
canNext: vue27.ComputedRef<boolean>;
|
|
25
|
+
canLast: vue27.ComputedRef<boolean>;
|
|
26
|
+
firstUrl: vue27.ComputedRef<string>;
|
|
27
|
+
prevUrl: vue27.ComputedRef<string>;
|
|
28
|
+
nextUrl: vue27.ComputedRef<string>;
|
|
29
|
+
lastUrl: vue27.ComputedRef<string>;
|
|
30
|
+
getUrl: (page: number) => string;
|
|
31
|
+
};
|
|
32
|
+
//#endregion
|
|
33
|
+
export { Paginator, usePagination };
|
|
@@ -1,2 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { computed, toValue } from "vue";
|
|
2
|
+
|
|
3
|
+
//#region src/pagination-vue/usePagination.ts
|
|
4
|
+
function usePagination(options) {
|
|
5
|
+
const total = computed(() => toValue(options.total));
|
|
6
|
+
const currentPage = computed(() => toValue(options.currentPage));
|
|
7
|
+
const perPage = computed(() => toValue(options.perPage || 12));
|
|
8
|
+
const totalPages = computed(() => Math.ceil(total.value / perPage.value));
|
|
9
|
+
const visiblePages = computed(() => Math.min(toValue(options.visiblePages || 5), totalPages.value));
|
|
10
|
+
const sideCount = computed(() => Math.floor(visiblePages.value / 2));
|
|
11
|
+
const items = computed(() => {
|
|
12
|
+
const items$1 = [];
|
|
13
|
+
let start = Math.max(1, currentPage.value - sideCount.value);
|
|
14
|
+
let end = Math.min(totalPages.value, currentPage.value + sideCount.value);
|
|
15
|
+
if (end - start + 1 < visiblePages.value && currentPage.value > 0) {
|
|
16
|
+
if (currentPage.value <= sideCount.value) end = Math.min(totalPages.value, start + visiblePages.value - 1);
|
|
17
|
+
else if (currentPage.value > totalPages.value - sideCount.value) start = Math.max(1, end - visiblePages.value + 1);
|
|
18
|
+
}
|
|
19
|
+
for (let i = start; i <= end; i++) items$1.push(i);
|
|
20
|
+
return items$1;
|
|
21
|
+
});
|
|
22
|
+
function getUrl(page) {
|
|
23
|
+
const url = new URL(options.url);
|
|
24
|
+
url.searchParams.set("page", String(page));
|
|
25
|
+
return url.toString();
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
items,
|
|
29
|
+
showPagination: computed(() => total.value > perPage.value),
|
|
30
|
+
currentPage,
|
|
31
|
+
canFirst: computed(() => currentPage.value > 1),
|
|
32
|
+
canPrev: computed(() => currentPage.value > 1),
|
|
33
|
+
canNext: computed(() => currentPage.value < totalPages.value),
|
|
34
|
+
canLast: computed(() => currentPage.value < totalPages.value),
|
|
35
|
+
firstUrl: computed(() => getUrl(1)),
|
|
36
|
+
prevUrl: computed(() => getUrl(currentPage.value - 1)),
|
|
37
|
+
nextUrl: computed(() => getUrl(currentPage.value + 1)),
|
|
38
|
+
lastUrl: computed(() => getUrl(totalPages.value)),
|
|
39
|
+
getUrl
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
//#endregion
|
|
44
|
+
export { usePagination };
|
|
@@ -1,2 +1,69 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/product-variant/types.d.ts
|
|
2
|
+
interface ProductVariant {
|
|
3
|
+
id: number;
|
|
4
|
+
/** 商品規格 Key */
|
|
5
|
+
combination_key: string | null;
|
|
6
|
+
/** 原價 */
|
|
7
|
+
listing_price: number;
|
|
8
|
+
/** 實際售價 */
|
|
9
|
+
selling_price: number;
|
|
10
|
+
/** 商品庫存數量 */
|
|
11
|
+
inventory: number;
|
|
12
|
+
}
|
|
13
|
+
interface ProductVariantAttribute {
|
|
14
|
+
id: number;
|
|
15
|
+
title: string;
|
|
16
|
+
options: ProductVariantAttributeOption[];
|
|
17
|
+
}
|
|
18
|
+
interface ProductVariantAttributeOption {
|
|
19
|
+
id: number;
|
|
20
|
+
title: string;
|
|
21
|
+
}
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/product-variant/ProductVariantSelector.d.ts
|
|
24
|
+
declare class ProductVariantSelector {
|
|
25
|
+
/**
|
|
26
|
+
* 可用的商品變體列表(所有 SKU)
|
|
27
|
+
*/
|
|
28
|
+
availableVariants: ProductVariant[];
|
|
29
|
+
/**
|
|
30
|
+
* 商品屬性選項列表(如顏色、尺寸等)
|
|
31
|
+
*/
|
|
32
|
+
variantAttributes: ProductVariantAttribute[];
|
|
33
|
+
/**
|
|
34
|
+
* 使用者已選擇的屬性值
|
|
35
|
+
*/
|
|
36
|
+
selectedAttributes: Record<number, {
|
|
37
|
+
optionId: number;
|
|
38
|
+
label: string;
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* 匹配到的商品規格物件
|
|
42
|
+
*/
|
|
43
|
+
currentVariant: ProductVariant | undefined;
|
|
44
|
+
constructor({
|
|
45
|
+
availableVariants,
|
|
46
|
+
variantAttributes
|
|
47
|
+
}: {
|
|
48
|
+
availableVariants: ProductVariant[];
|
|
49
|
+
variantAttributes: ProductVariantAttribute[];
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* 選擇商品規格
|
|
53
|
+
*/
|
|
54
|
+
selectVariant(attributeId: number, optionId: number, label: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* 獲取已選擇的商品規格選項標籤
|
|
57
|
+
*/
|
|
58
|
+
getSelectedAttributesLabel(): string;
|
|
59
|
+
/**
|
|
60
|
+
* 確認是否已選擇所有商品規格選項
|
|
61
|
+
*/
|
|
62
|
+
areAllAttributesSelected(): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* 確認是否有足夠的庫存
|
|
65
|
+
*/
|
|
66
|
+
hasEnoughStock(stock: number): boolean;
|
|
67
|
+
}
|
|
68
|
+
//#endregion
|
|
69
|
+
export { ProductVariant, ProductVariantAttribute, ProductVariantAttributeOption, ProductVariantSelector };
|
|
@@ -1,2 +1,57 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/product-variant/ProductVariantSelector.ts
|
|
2
|
+
var ProductVariantSelector = class {
|
|
3
|
+
/**
|
|
4
|
+
* 可用的商品變體列表(所有 SKU)
|
|
5
|
+
*/
|
|
6
|
+
availableVariants = [];
|
|
7
|
+
/**
|
|
8
|
+
* 商品屬性選項列表(如顏色、尺寸等)
|
|
9
|
+
*/
|
|
10
|
+
variantAttributes = [];
|
|
11
|
+
/**
|
|
12
|
+
* 使用者已選擇的屬性值
|
|
13
|
+
*/
|
|
14
|
+
selectedAttributes = {};
|
|
15
|
+
/**
|
|
16
|
+
* 匹配到的商品規格物件
|
|
17
|
+
*/
|
|
18
|
+
currentVariant = void 0;
|
|
19
|
+
constructor({ availableVariants, variantAttributes }) {
|
|
20
|
+
this.availableVariants = availableVariants;
|
|
21
|
+
this.variantAttributes = variantAttributes;
|
|
22
|
+
if (availableVariants.length === 1 && availableVariants[0].combination_key === null) this.currentVariant = availableVariants[0];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 選擇商品規格
|
|
26
|
+
*/
|
|
27
|
+
selectVariant(attributeId, optionId, label) {
|
|
28
|
+
this.selectedAttributes[attributeId] = {
|
|
29
|
+
optionId,
|
|
30
|
+
label
|
|
31
|
+
};
|
|
32
|
+
const variantCombinationKey = Object.values(this.selectedAttributes).map((attr) => attr.optionId).sort((a, b) => a - b).join("-");
|
|
33
|
+
this.currentVariant = this.availableVariants.find((variant) => variant.combination_key === variantCombinationKey);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 獲取已選擇的商品規格選項標籤
|
|
37
|
+
*/
|
|
38
|
+
getSelectedAttributesLabel() {
|
|
39
|
+
return Object.values(this.selectedAttributes).map((attr) => attr.label).join(", ");
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 確認是否已選擇所有商品規格選項
|
|
43
|
+
*/
|
|
44
|
+
areAllAttributesSelected() {
|
|
45
|
+
return Object.keys(this.selectedAttributes).length === this.variantAttributes.length;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 確認是否有足夠的庫存
|
|
49
|
+
*/
|
|
50
|
+
hasEnoughStock(stock) {
|
|
51
|
+
const specificationStock = this.currentVariant?.inventory || 0;
|
|
52
|
+
return specificationStock > 0 && specificationStock >= stock;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { ProductVariantSelector };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
import type { UrlConfig } from '
|
|
2
|
+
import type { UrlConfig } from '@stephenchenorg/astro/query-params'
|
|
3
3
|
|
|
4
4
|
interface Props {
|
|
5
5
|
config: UrlConfig
|
|
@@ -18,7 +18,6 @@ window.__astro_provide_url_config__ = config;
|
|
|
18
18
|
</script>
|
|
19
19
|
|
|
20
20
|
<script>
|
|
21
|
-
// Must be imported from the regular package path to avoid duplicate instances
|
|
22
21
|
import { urlConfigStore } from '@stephenchenorg/astro/query-params'
|
|
23
22
|
|
|
24
23
|
const props = window.__astro_provide_url_config__
|
|
@@ -1,6 +1,35 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import * as nanostores4 from "nanostores";
|
|
2
|
+
import qs from "query-string";
|
|
3
|
+
|
|
4
|
+
//#region src/query-params/types.d.ts
|
|
5
|
+
interface UrlConfig {
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
hash?: string;
|
|
8
|
+
params: Record<string, any>;
|
|
9
|
+
defaultParams?: Record<string, any>;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/query-params/config.d.ts
|
|
13
|
+
declare function createUrlConfig(config: UrlConfig): UrlConfig;
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/query-params/store.d.ts
|
|
16
|
+
declare const urlConfigStore: nanostores4.PreinitializedWritableAtom<UrlConfig> & object;
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/query-params/url.d.ts
|
|
19
|
+
declare global {
|
|
20
|
+
interface Window {
|
|
21
|
+
__astro_provide_url_config__?: UrlConfig;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
interface QueryParamsUrlOptions {
|
|
25
|
+
clear?: boolean;
|
|
26
|
+
transformParams?: (params: Record<string, any>) => Record<string, any>;
|
|
27
|
+
}
|
|
28
|
+
declare function queryParamsUrl(additionalParams: Record<string, any>, urlConfig?: UrlConfig, options?: QueryParamsUrlOptions): string;
|
|
29
|
+
declare function parseQueryParams(search: string): qs.ParsedQuery<string>;
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/query-params/utils.d.ts
|
|
32
|
+
declare function mergeUrlParams<Params extends Record<string, any> = Record<string, any>>(baseParams: Params, userParams: Partial<Params>): Params;
|
|
33
|
+
declare function cleanParams(params: Record<string, any>, defaultParams: Record<string, any>): Record<string, any>;
|
|
34
|
+
//#endregion
|
|
35
|
+
export { QueryParamsUrlOptions, UrlConfig, cleanParams, createUrlConfig, mergeUrlParams, parseQueryParams, queryParamsUrl, urlConfigStore };
|
|
@@ -1,6 +1,62 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { atom } from "nanostores";
|
|
2
|
+
import qs from "query-string";
|
|
3
|
+
|
|
4
|
+
//#region src/query-params/config.ts
|
|
5
|
+
function createUrlConfig(config) {
|
|
6
|
+
return config;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
//#endregion
|
|
10
|
+
//#region src/query-params/store.ts
|
|
11
|
+
const urlConfigStore = atom({
|
|
12
|
+
baseUrl: "",
|
|
13
|
+
hash: "",
|
|
14
|
+
params: {},
|
|
15
|
+
defaultParams: {}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/query-params/utils.ts
|
|
20
|
+
function mergeUrlParams(baseParams, userParams) {
|
|
21
|
+
return Object.keys(baseParams).reduce((result, key) => {
|
|
22
|
+
if (userParams[key] === null) result[key] = null;
|
|
23
|
+
else if (Array.isArray(baseParams[key])) result[key] = Array.from(new Set([...baseParams[key], ...userParams[key] || []]));
|
|
24
|
+
else result[key] = typeof userParams[key] !== "undefined" ? userParams[key] : baseParams[key];
|
|
25
|
+
return result;
|
|
26
|
+
}, {});
|
|
27
|
+
}
|
|
28
|
+
function cleanParams(params, defaultParams) {
|
|
29
|
+
const newParams = JSON.parse(JSON.stringify(params));
|
|
30
|
+
Object.keys(newParams).forEach((key) => {
|
|
31
|
+
if (Object.keys(defaultParams).includes(key) && newParams[key] === defaultParams[key]) newParams[key] = null;
|
|
32
|
+
});
|
|
33
|
+
return newParams;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region src/query-params/url.ts
|
|
38
|
+
function queryParamsUrl(additionalParams, urlConfig = {
|
|
39
|
+
baseUrl: "",
|
|
40
|
+
params: {}
|
|
41
|
+
}, options = {}) {
|
|
42
|
+
const { clear = false, transformParams } = options;
|
|
43
|
+
const config = typeof window !== "undefined" ? urlConfigStore.get() : urlConfig;
|
|
44
|
+
let params = {};
|
|
45
|
+
if (!clear) {
|
|
46
|
+
params = mergeUrlParams(config.params, additionalParams);
|
|
47
|
+
if (transformParams) params = transformParams(params);
|
|
48
|
+
params = cleanParams(params, config.defaultParams || {});
|
|
49
|
+
}
|
|
50
|
+
const queryString = qs.stringify(params, {
|
|
51
|
+
skipEmptyString: true,
|
|
52
|
+
skipNull: true,
|
|
53
|
+
sort: false
|
|
54
|
+
});
|
|
55
|
+
return `${config.baseUrl}${queryString ? "?" : ""}${queryString}${config.hash ? `#${config.hash}` : ""}`;
|
|
56
|
+
}
|
|
57
|
+
function parseQueryParams(search) {
|
|
58
|
+
return qs.parse(search);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
//#endregion
|
|
62
|
+
export { cleanParams, createUrlConfig, mergeUrlParams, parseQueryParams, queryParamsUrl, urlConfigStore };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stephenchenorg/astro",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "6.0.0",
|
|
5
5
|
"description": "Stephenchenorg Astro 前端通用套件",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://stephenchenorg-astro.netlify.app",
|
|
@@ -29,10 +29,13 @@
|
|
|
29
29
|
"types": "./dist/image/index.d.ts",
|
|
30
30
|
"import": "./dist/image/index.js"
|
|
31
31
|
},
|
|
32
|
+
"./image/components/Image.astro": "./dist/image/components/Image.astro",
|
|
33
|
+
"./image/components/ResponsiveImage.astro": "./dist/image/components/ResponsiveImage.astro",
|
|
32
34
|
"./page": {
|
|
33
35
|
"types": "./dist/page/index.d.ts",
|
|
34
36
|
"import": "./dist/page/index.js"
|
|
35
37
|
},
|
|
38
|
+
"./page/components/PageFieldRender.astro": "./dist/page/components/PageFieldRender.astro",
|
|
36
39
|
"./pagination-astro": {
|
|
37
40
|
"types": "./dist/pagination-astro/index.d.ts",
|
|
38
41
|
"import": "./dist/pagination-astro/index.js"
|
|
@@ -48,7 +51,8 @@
|
|
|
48
51
|
"./query-params": {
|
|
49
52
|
"types": "./dist/query-params/index.d.ts",
|
|
50
53
|
"import": "./dist/query-params/index.js"
|
|
51
|
-
}
|
|
54
|
+
},
|
|
55
|
+
"./query-params/components/ProvideUrlConfig.astro": "./dist/query-params/components/ProvideUrlConfig.astro"
|
|
52
56
|
},
|
|
53
57
|
"typesVersions": {
|
|
54
58
|
"*": {
|
|
@@ -67,16 +71,16 @@
|
|
|
67
71
|
"node": ">=22"
|
|
68
72
|
},
|
|
69
73
|
"scripts": {
|
|
70
|
-
"build": "
|
|
74
|
+
"build": "tsdown",
|
|
71
75
|
"lint": "eslint \"*.{js,ts,json}\" \"src/**/*.ts\"",
|
|
72
|
-
"code-check": "astro check && npm run lint",
|
|
73
76
|
"test": "vitest",
|
|
77
|
+
"code-check": "astro check && npm run lint && npm run test -- --run",
|
|
74
78
|
"prepack": "npm run build",
|
|
75
79
|
"release": "bumpp --commit \"Release v%s\" && npm publish"
|
|
76
80
|
},
|
|
77
81
|
"peerDependencies": {
|
|
78
82
|
"astro": "^5.0.0",
|
|
79
|
-
"vue": "^3.
|
|
83
|
+
"vue": "^3.5.0"
|
|
80
84
|
},
|
|
81
85
|
"peerDependenciesMeta": {
|
|
82
86
|
"vue": {
|
|
@@ -99,7 +103,7 @@
|
|
|
99
103
|
"bumpp": "^10.2.0",
|
|
100
104
|
"eslint": "^9.30.1",
|
|
101
105
|
"eslint-plugin-astro": "^1.3.1",
|
|
102
|
-
"
|
|
106
|
+
"tsdown": "^0.12.9",
|
|
103
107
|
"typescript": "^5.8.3",
|
|
104
108
|
"vitest": "^3.2.4",
|
|
105
109
|
"vue": "^3.5.17"
|
package/dist/api/error.d.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
export interface GraphQLFieldError {
|
|
2
|
-
code?: number;
|
|
3
|
-
message: string;
|
|
4
|
-
locations?: {
|
|
5
|
-
line: number;
|
|
6
|
-
column: number;
|
|
7
|
-
}[];
|
|
8
|
-
path?: (string | number)[];
|
|
9
|
-
extensions?: GraphQLRequestExtensions;
|
|
10
|
-
data?: Record<string, any>;
|
|
11
|
-
}
|
|
12
|
-
export interface GraphQLRequestExtensions {
|
|
13
|
-
debugMessage?: string;
|
|
14
|
-
file?: string;
|
|
15
|
-
line?: number;
|
|
16
|
-
trace?: {
|
|
17
|
-
file: string;
|
|
18
|
-
line: number;
|
|
19
|
-
call: number;
|
|
20
|
-
}[];
|
|
21
|
-
}
|
|
22
|
-
export interface GraphQLRequestErrorOptions {
|
|
23
|
-
code?: number;
|
|
24
|
-
message: string;
|
|
25
|
-
query: string;
|
|
26
|
-
variables?: Record<string, any>;
|
|
27
|
-
extensions?: GraphQLRequestExtensions;
|
|
28
|
-
fieldErrors?: GraphQLFieldError[];
|
|
29
|
-
}
|
|
30
|
-
export declare class GraphQLRequestError extends Error {
|
|
31
|
-
type: string;
|
|
32
|
-
name: string;
|
|
33
|
-
title: string;
|
|
34
|
-
code: number | undefined;
|
|
35
|
-
originalMessage: string;
|
|
36
|
-
query: string;
|
|
37
|
-
variables: Record<string, any> | undefined;
|
|
38
|
-
extensions: GraphQLRequestExtensions | undefined;
|
|
39
|
-
fieldErrors: GraphQLFieldError[] | undefined;
|
|
40
|
-
constructor(props: GraphQLRequestErrorOptions, options?: ErrorOptions);
|
|
41
|
-
isNotFound(): boolean;
|
|
42
|
-
private buildMessage;
|
|
43
|
-
static is(err: unknown): err is GraphQLRequestError;
|
|
44
|
-
}
|
|
45
|
-
export declare class GraphQLNotFoundError extends GraphQLRequestError {
|
|
46
|
-
type: string;
|
|
47
|
-
name: string;
|
|
48
|
-
}
|
|
49
|
-
export declare class GraphQLValidationError extends GraphQLRequestError {
|
|
50
|
-
type: string;
|
|
51
|
-
name: string;
|
|
52
|
-
errors: Record<string, string[]>;
|
|
53
|
-
constructor(props: GraphQLRequestErrorOptions, options?: ErrorOptions);
|
|
54
|
-
}
|