@stephenchenorg/astro-graphql 9.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/LICENSE.md +21 -0
- package/README.md +42 -0
- package/dist/api/index.d.ts +76 -0
- package/dist/api/index.js +139 -0
- package/dist/company-setting/index.d.ts +6 -0
- package/dist/company-setting/index.js +25 -0
- package/dist/image/components/Image.astro +10 -0
- package/dist/image/components/ResponsiveImage.astro +41 -0
- package/dist/image/index.d.ts +16 -0
- package/dist/image/index.js +30 -0
- package/dist/page/components/PageFieldRender.astro +34 -0
- package/dist/page/index.d.ts +81 -0
- package/dist/page/index.js +71 -0
- package/package.json +76 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-present Lucas Yang <yangchenshin77@gmail.com>
|
|
4
|
+
|
|
5
|
+
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
> of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
> in the Software without restriction, including without limitation the rights
|
|
8
|
+
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
> copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
> furnished to do so, subject to the following conditions:
|
|
11
|
+
>
|
|
12
|
+
> The above copyright notice and this permission notice shall be included in
|
|
13
|
+
> all copies or substantial portions of the Software.
|
|
14
|
+
>
|
|
15
|
+
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
> THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Stephenchenorg Astro 前端 GraphQL 整合串接套件
|
|
2
|
+
|
|
3
|
+
[![NPM version][ico-version]][link-npm]
|
|
4
|
+
[![Software License][ico-license]](LICENSE)
|
|
5
|
+
[![Total Downloads][ico-downloads]][link-downloads]
|
|
6
|
+
|
|
7
|
+
## 安裝
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# npm
|
|
11
|
+
npm install @stephenchenorg/astro-graphql
|
|
12
|
+
# yarn
|
|
13
|
+
yarn add @stephenchenorg/astro-graphql
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## 文件
|
|
17
|
+
|
|
18
|
+
https://stephenchenorg-astro.netlify.app
|
|
19
|
+
|
|
20
|
+
## 開發
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
yarn
|
|
24
|
+
yarn build
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 發布套件
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm login
|
|
31
|
+
npm run release
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## License
|
|
35
|
+
|
|
36
|
+
[MIT LICENSE](LICENSE.md)
|
|
37
|
+
|
|
38
|
+
[ico-version]: https://img.shields.io/npm/v/@stephenchenorg/astro-graphql?style=flat-square
|
|
39
|
+
[ico-license]: https://img.shields.io/badge/license-MIT-brightgreen?style=flat-square
|
|
40
|
+
[ico-downloads]: https://img.shields.io/npm/dt/@stephenchenorg/astro-graphql?style=flat-square
|
|
41
|
+
[link-npm]: https://www.npmjs.com/package/@stephenchenorg/astro-graphql
|
|
42
|
+
[link-downloads]: https://www.npmjs.com/package/@stephenchenorg/astro-graphql
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { gql } from "graphql-tag";
|
|
2
|
+
import { TypedDocumentNode } from "@graphql-typed-document-node/core";
|
|
3
|
+
import { APIContext } from "astro";
|
|
4
|
+
|
|
5
|
+
//#region src/api/error.d.ts
|
|
6
|
+
interface GraphQLFieldError {
|
|
7
|
+
code?: number;
|
|
8
|
+
message: string;
|
|
9
|
+
locations?: {
|
|
10
|
+
line: number;
|
|
11
|
+
column: number;
|
|
12
|
+
}[];
|
|
13
|
+
path?: (string | number)[];
|
|
14
|
+
extensions?: GraphQLRequestExtensions;
|
|
15
|
+
data?: Record<string, any>;
|
|
16
|
+
}
|
|
17
|
+
interface GraphQLRequestExtensions {
|
|
18
|
+
debugMessage?: string;
|
|
19
|
+
file?: string;
|
|
20
|
+
line?: number;
|
|
21
|
+
trace?: {
|
|
22
|
+
file: string;
|
|
23
|
+
line: number;
|
|
24
|
+
call: number;
|
|
25
|
+
}[];
|
|
26
|
+
}
|
|
27
|
+
interface GraphQLRequestErrorOptions {
|
|
28
|
+
code?: number;
|
|
29
|
+
message: string;
|
|
30
|
+
query: string;
|
|
31
|
+
variables?: Record<string, any>;
|
|
32
|
+
extensions?: GraphQLRequestExtensions;
|
|
33
|
+
fieldErrors?: GraphQLFieldError[];
|
|
34
|
+
}
|
|
35
|
+
declare class GraphQLRequestError extends Error {
|
|
36
|
+
type: string;
|
|
37
|
+
name: string;
|
|
38
|
+
title: string;
|
|
39
|
+
code: number | undefined;
|
|
40
|
+
originalMessage: string;
|
|
41
|
+
query: string;
|
|
42
|
+
variables: Record<string, any> | undefined;
|
|
43
|
+
extensions: GraphQLRequestExtensions | undefined;
|
|
44
|
+
fieldErrors: GraphQLFieldError[] | undefined;
|
|
45
|
+
constructor(props: GraphQLRequestErrorOptions, options?: ErrorOptions);
|
|
46
|
+
isNotFound(): boolean;
|
|
47
|
+
private buildMessage;
|
|
48
|
+
static is(err: unknown): err is GraphQLRequestError;
|
|
49
|
+
}
|
|
50
|
+
declare class GraphQLNotFoundError extends GraphQLRequestError {
|
|
51
|
+
type: string;
|
|
52
|
+
name: string;
|
|
53
|
+
}
|
|
54
|
+
declare class GraphQLValidationError extends GraphQLRequestError {
|
|
55
|
+
type: string;
|
|
56
|
+
name: string;
|
|
57
|
+
errors: Record<string, string[]>;
|
|
58
|
+
constructor(props: GraphQLRequestErrorOptions, options?: ErrorOptions);
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/api/errorResponse.d.ts
|
|
62
|
+
declare function handleErrorResponse(e: unknown): Response | undefined;
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/api/fetch.d.ts
|
|
65
|
+
interface CreateGraphQLAPIOptions {
|
|
66
|
+
endpoint: string;
|
|
67
|
+
defaultVariables?: Record<string, any> | ((astroContext?: APIContext) => Record<string, any>);
|
|
68
|
+
fetchOptions?: RequestInit | ((astroContext?: APIContext) => RequestInit);
|
|
69
|
+
}
|
|
70
|
+
declare function createGraphQLAPI(globalOptions: CreateGraphQLAPIOptions): <TData extends Record<string, any>, TVariables extends Record<string, any> = Record<string, any>>(query: TypedDocumentNode<TData, TVariables>, options?: {
|
|
71
|
+
variables?: TVariables;
|
|
72
|
+
fetchOptions?: RequestInit;
|
|
73
|
+
Astro?: APIContext;
|
|
74
|
+
}) => Promise<TData>;
|
|
75
|
+
//#endregion
|
|
76
|
+
export { CreateGraphQLAPIOptions, GraphQLFieldError, GraphQLNotFoundError, GraphQLRequestError, GraphQLRequestErrorOptions, GraphQLRequestExtensions, GraphQLValidationError, createGraphQLAPI, gql, handleErrorResponse };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { AwesomeGraphQLClient, GraphQLRequestError as GraphQLRequestError$1 } from "awesome-graphql-client";
|
|
2
|
+
import { print } from "graphql/language/printer";
|
|
3
|
+
import { gql } from "graphql-tag";
|
|
4
|
+
|
|
5
|
+
//#region src/api/error.ts
|
|
6
|
+
var GraphQLRequestError = class extends Error {
|
|
7
|
+
type = "GraphQLRequestError";
|
|
8
|
+
name = "GraphQLRequestError";
|
|
9
|
+
title = "GraphQL request error.";
|
|
10
|
+
code;
|
|
11
|
+
originalMessage;
|
|
12
|
+
query;
|
|
13
|
+
variables;
|
|
14
|
+
extensions;
|
|
15
|
+
fieldErrors;
|
|
16
|
+
constructor(props, options) {
|
|
17
|
+
const { code, message, query, variables, extensions, fieldErrors } = props;
|
|
18
|
+
super("GraphQL request error.", options);
|
|
19
|
+
const originalStack = this.stack;
|
|
20
|
+
this.title = "GraphQL request error.";
|
|
21
|
+
this.code = code;
|
|
22
|
+
this.originalMessage = message;
|
|
23
|
+
this.query = query;
|
|
24
|
+
this.variables = variables;
|
|
25
|
+
this.extensions = extensions;
|
|
26
|
+
this.fieldErrors = fieldErrors;
|
|
27
|
+
this.message = this.buildMessage();
|
|
28
|
+
this.stack = originalStack;
|
|
29
|
+
}
|
|
30
|
+
isNotFound() {
|
|
31
|
+
return this.originalMessage.includes("Http Status 404");
|
|
32
|
+
}
|
|
33
|
+
buildMessage() {
|
|
34
|
+
let message = `${this.originalMessage}\n`;
|
|
35
|
+
if (this.code) {
|
|
36
|
+
message += "\n";
|
|
37
|
+
message += `[code]\n${this.code}\n`;
|
|
38
|
+
}
|
|
39
|
+
if (this.extensions) {
|
|
40
|
+
if (this.extensions.debugMessage) {
|
|
41
|
+
message += "\n";
|
|
42
|
+
message += `${this.extensions.debugMessage}\n`;
|
|
43
|
+
}
|
|
44
|
+
if (this.extensions.file || this.extensions.line || this.extensions.trace) {
|
|
45
|
+
message += "\n";
|
|
46
|
+
message += "[stacktrace]\n";
|
|
47
|
+
if (this.extensions.file) message += `file: ${this.extensions.file}\n`;
|
|
48
|
+
if (this.extensions.line) message += `line: ${this.extensions.line}\n`;
|
|
49
|
+
if (this.extensions.trace && Array.isArray(this.extensions.trace)) {
|
|
50
|
+
message += "trace:\n";
|
|
51
|
+
for (const trace of this.extensions.trace.slice(0, 3)) {
|
|
52
|
+
message += ` - file: ${trace.file}\n`;
|
|
53
|
+
message += ` line: ${trace.line}\n`;
|
|
54
|
+
message += ` call: ${trace.call}\n`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (this.query) {
|
|
60
|
+
message += "\n";
|
|
61
|
+
message += `[query]\n${this.query}\n`;
|
|
62
|
+
}
|
|
63
|
+
if (this.variables) {
|
|
64
|
+
message += "\n";
|
|
65
|
+
message += `[variables]\n${JSON.stringify(this.variables, null, 2)}\n`;
|
|
66
|
+
}
|
|
67
|
+
return message;
|
|
68
|
+
}
|
|
69
|
+
static is(err) {
|
|
70
|
+
return err.type === "GraphQLRequestError";
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var GraphQLNotFoundError = class extends GraphQLRequestError {
|
|
74
|
+
type = "GraphQLNotFoundError";
|
|
75
|
+
name = "GraphQLNotFoundError";
|
|
76
|
+
};
|
|
77
|
+
var GraphQLValidationError = class extends GraphQLRequestError {
|
|
78
|
+
type = "GraphQLValidationError";
|
|
79
|
+
name = "GraphQLValidationError";
|
|
80
|
+
errors;
|
|
81
|
+
constructor(props, options) {
|
|
82
|
+
super(props, options);
|
|
83
|
+
this.errors = this.fieldErrors?.[0]?.data?.validation || {};
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/api/errorResponse.ts
|
|
89
|
+
function handleErrorResponse(e) {
|
|
90
|
+
if (e instanceof GraphQLNotFoundError) return new Response(null, {
|
|
91
|
+
status: 404,
|
|
92
|
+
statusText: "Not found"
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/api/fetch.ts
|
|
98
|
+
function createGraphQLAPI(globalOptions) {
|
|
99
|
+
const client = new AwesomeGraphQLClient({
|
|
100
|
+
endpoint: globalOptions.endpoint,
|
|
101
|
+
formatQuery: (query) => print(query)
|
|
102
|
+
});
|
|
103
|
+
return function graphQLAPI(query, options) {
|
|
104
|
+
const { variables, fetchOptions, Astro: astroContext } = options || {};
|
|
105
|
+
const defaultVariables = typeof globalOptions.defaultVariables === "function" ? globalOptions.defaultVariables(astroContext) : globalOptions.defaultVariables;
|
|
106
|
+
const defaultFetchOptions = typeof globalOptions.fetchOptions === "function" ? globalOptions.fetchOptions(astroContext) : globalOptions.fetchOptions;
|
|
107
|
+
return new Promise((resolve, reject) => {
|
|
108
|
+
client.request(query, {
|
|
109
|
+
...defaultVariables,
|
|
110
|
+
...variables
|
|
111
|
+
}, {
|
|
112
|
+
...defaultFetchOptions,
|
|
113
|
+
...fetchOptions,
|
|
114
|
+
headers: {
|
|
115
|
+
...defaultFetchOptions?.headers,
|
|
116
|
+
...fetchOptions?.headers
|
|
117
|
+
}
|
|
118
|
+
}).then((data) => resolve(data)).catch((error) => {
|
|
119
|
+
if (error instanceof GraphQLRequestError$1) {
|
|
120
|
+
const code = (error.fieldErrors?.[0])?.code;
|
|
121
|
+
const errorProps = {
|
|
122
|
+
code,
|
|
123
|
+
message: error.message,
|
|
124
|
+
query: error.query,
|
|
125
|
+
variables: error.variables,
|
|
126
|
+
extensions: error.extensions,
|
|
127
|
+
fieldErrors: error.fieldErrors
|
|
128
|
+
};
|
|
129
|
+
if (code === 404) reject(new GraphQLNotFoundError(errorProps));
|
|
130
|
+
else if (code === 422) reject(new GraphQLValidationError(errorProps));
|
|
131
|
+
reject(new GraphQLRequestError(errorProps));
|
|
132
|
+
} else reject(error);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
//#endregion
|
|
139
|
+
export { GraphQLNotFoundError, GraphQLRequestError, GraphQLValidationError, createGraphQLAPI, gql, handleErrorResponse };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { gql } from "graphql-tag";
|
|
2
|
+
|
|
3
|
+
//#region src/company-setting/fragments.ts
|
|
4
|
+
const companySettingFields = gql`
|
|
5
|
+
fragment CompanySettingFields on CompanySetting {
|
|
6
|
+
lang
|
|
7
|
+
name
|
|
8
|
+
description
|
|
9
|
+
logo
|
|
10
|
+
address_1
|
|
11
|
+
address_2
|
|
12
|
+
email_1
|
|
13
|
+
email_2
|
|
14
|
+
fb_link
|
|
15
|
+
ig_link
|
|
16
|
+
line_link
|
|
17
|
+
phone_1
|
|
18
|
+
phone_2
|
|
19
|
+
twitter_link
|
|
20
|
+
threads_link
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { companySettingFields };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
---
|
|
2
|
+
interface Props extends astroHTML.JSX.ImgHTMLAttributes {
|
|
3
|
+
desktop: string | null
|
|
4
|
+
desktopBlur?: string | null
|
|
5
|
+
mobile?: string | null
|
|
6
|
+
mobileBlur?: string | null
|
|
7
|
+
|
|
8
|
+
// GraphQL image props
|
|
9
|
+
desktop_blur?: string | null
|
|
10
|
+
mobile_blur?: string | null
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const {
|
|
14
|
+
desktop,
|
|
15
|
+
desktopBlur: _desktopBlur,
|
|
16
|
+
mobile,
|
|
17
|
+
mobileBlur: _mobileBlur,
|
|
18
|
+
|
|
19
|
+
desktop_blur: _desktop_blur,
|
|
20
|
+
mobile_blur: _mobile_blur,
|
|
21
|
+
src: _src,
|
|
22
|
+
|
|
23
|
+
...attributes
|
|
24
|
+
} = Astro.props
|
|
25
|
+
|
|
26
|
+
// const desktopBlur = Astro.props.desktopBlur || Astro.props.desktop_blur
|
|
27
|
+
// const mobileBlur = Astro.props.mobileBlur || Astro.props.mobile_blur
|
|
28
|
+
|
|
29
|
+
const breakpoint = 768
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
{desktop && (
|
|
33
|
+
mobile ? (
|
|
34
|
+
<picture>
|
|
35
|
+
{mobile && <source media={`(max-width: ${breakpoint - 0.02}px)`} srcset={mobile} />}
|
|
36
|
+
<img src={desktop} {...attributes} />
|
|
37
|
+
</picture>
|
|
38
|
+
) : (
|
|
39
|
+
<img src={desktop} {...attributes} />
|
|
40
|
+
)
|
|
41
|
+
)}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as graphql0 from "graphql";
|
|
2
|
+
|
|
3
|
+
//#region src/image/fragments.d.ts
|
|
4
|
+
declare const imageFields: graphql0.DocumentNode;
|
|
5
|
+
declare const coverFields: graphql0.DocumentNode;
|
|
6
|
+
declare const backgroundFields: graphql0.DocumentNode;
|
|
7
|
+
//#endregion
|
|
8
|
+
//#region src/image/types.d.ts
|
|
9
|
+
interface ImageSource {
|
|
10
|
+
desktop: string | null;
|
|
11
|
+
desktop_blur: string | null;
|
|
12
|
+
mobile: string | null;
|
|
13
|
+
mobile_blur: string | null;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { ImageSource, backgroundFields, coverFields, imageFields };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { gql } from "graphql-tag";
|
|
2
|
+
|
|
3
|
+
//#region src/image/fragments.ts
|
|
4
|
+
const imageFields = gql`
|
|
5
|
+
fragment ImageFields on Image {
|
|
6
|
+
desktop
|
|
7
|
+
desktop_blur
|
|
8
|
+
mobile
|
|
9
|
+
mobile_blur
|
|
10
|
+
}
|
|
11
|
+
`;
|
|
12
|
+
const coverFields = gql`
|
|
13
|
+
fragment CoverFields on Cover {
|
|
14
|
+
desktop
|
|
15
|
+
desktop_blur
|
|
16
|
+
mobile
|
|
17
|
+
mobile_blur
|
|
18
|
+
}
|
|
19
|
+
`;
|
|
20
|
+
const backgroundFields = gql`
|
|
21
|
+
fragment BackgroundFields on Background {
|
|
22
|
+
desktop
|
|
23
|
+
desktop_blur
|
|
24
|
+
mobile
|
|
25
|
+
mobile_blur
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
export { backgroundFields, coverFields, imageFields };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { PageField } from '@stephenchenorg/astro-graphql/page'
|
|
3
|
+
import ResponsiveImage from '@stephenchenorg/astro-graphql/image/components/ResponsiveImage.astro'
|
|
4
|
+
import { isContentField, isImageField, isPlainTextareaField, isPlainTextField } from '@stephenchenorg/astro-graphql/page'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
fields: PageField[]
|
|
8
|
+
key: string
|
|
9
|
+
attributes?: Record<string, any>
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const { fields, key, attributes } = Astro.props
|
|
13
|
+
|
|
14
|
+
const field = fields.find(field => field.key === key)
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
{
|
|
18
|
+
field && (
|
|
19
|
+
isPlainTextField(field) ? <Fragment set:text={field.content} />
|
|
20
|
+
: isPlainTextareaField(field) ? <Fragment set:html={field.content} />
|
|
21
|
+
: isContentField(field) ? <Fragment set:html={field.content} />
|
|
22
|
+
: isImageField(field) ? (
|
|
23
|
+
<ResponsiveImage
|
|
24
|
+
desktop={field.image.desktop}
|
|
25
|
+
desktopBlur={field.image.desktop_blur}
|
|
26
|
+
mobile={field.image.mobile}
|
|
27
|
+
mobileBlur={field.image.mobile_blur}
|
|
28
|
+
alt={`Image of ${key}`}
|
|
29
|
+
{...attributes}
|
|
30
|
+
/>
|
|
31
|
+
)
|
|
32
|
+
: null
|
|
33
|
+
)
|
|
34
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as graphql4 from "graphql";
|
|
2
|
+
import { PageMeta } from "@stephenchenorg/astro/page";
|
|
3
|
+
|
|
4
|
+
//#region src/page/field/fragments.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Page fields fragment requires explicit import image
|
|
7
|
+
* fields fragment `imageFields` from Image module.
|
|
8
|
+
*/
|
|
9
|
+
declare const pageFields: graphql4.DocumentNode;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/page/types.d.ts
|
|
12
|
+
interface DataPage {
|
|
13
|
+
page: Page;
|
|
14
|
+
}
|
|
15
|
+
interface Page extends PageMeta {
|
|
16
|
+
fields: PageField[];
|
|
17
|
+
}
|
|
18
|
+
interface PageField {
|
|
19
|
+
key: string;
|
|
20
|
+
type: 'text' | 'textarea' | 'html' | 'image';
|
|
21
|
+
content: string | null;
|
|
22
|
+
image: {
|
|
23
|
+
desktop: string | null;
|
|
24
|
+
desktop_blur: string | null;
|
|
25
|
+
mobile: string | null;
|
|
26
|
+
mobile_blur: string | null;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
interface PagePlainTextField extends PageField {
|
|
30
|
+
type: 'text';
|
|
31
|
+
content: string;
|
|
32
|
+
image: {
|
|
33
|
+
desktop: null;
|
|
34
|
+
desktop_blur: null;
|
|
35
|
+
mobile: null;
|
|
36
|
+
mobile_blur: null;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
interface PagePlainTextareaField extends PageField {
|
|
40
|
+
type: 'textarea';
|
|
41
|
+
content: string;
|
|
42
|
+
image: {
|
|
43
|
+
desktop: null;
|
|
44
|
+
desktop_blur: null;
|
|
45
|
+
mobile: null;
|
|
46
|
+
mobile_blur: null;
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
interface PageContentField extends PageField {
|
|
50
|
+
type: 'html';
|
|
51
|
+
content: string;
|
|
52
|
+
image: {
|
|
53
|
+
desktop: null;
|
|
54
|
+
desktop_blur: null;
|
|
55
|
+
mobile: null;
|
|
56
|
+
mobile_blur: null;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
interface PageImageField extends PageField {
|
|
60
|
+
type: 'image';
|
|
61
|
+
content: null;
|
|
62
|
+
image: {
|
|
63
|
+
desktop: string;
|
|
64
|
+
desktop_blur: string;
|
|
65
|
+
mobile: string;
|
|
66
|
+
mobile_blur: string;
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/page/field/helpers.d.ts
|
|
71
|
+
declare function isPlainTextField(field: PageField): field is PagePlainTextField;
|
|
72
|
+
declare function isPlainTextareaField(field: PageField): field is PagePlainTextareaField;
|
|
73
|
+
declare function isContentField(field: PageField): field is PageContentField;
|
|
74
|
+
declare function isImageField(field: PageField): field is PageImageField;
|
|
75
|
+
declare function pageTextField(fields: PageField[], key: string): string | null;
|
|
76
|
+
declare function pageImageFieldForBackground(fields: PageField[], key: string): string;
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/page/seo-meta/fragments.d.ts
|
|
79
|
+
declare const seoMetaFields: (dummyClass: string) => graphql4.DocumentNode;
|
|
80
|
+
//#endregion
|
|
81
|
+
export { DataPage, Page, PageContentField, PageField, PageImageField, PagePlainTextField, PagePlainTextareaField, isContentField, isImageField, isPlainTextField, isPlainTextareaField, pageFields, pageImageFieldForBackground, pageTextField, seoMetaFields };
|
|
@@ -0,0 +1,71 @@
|
|
|
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
|
+
export { isContentField, isImageField, isPlainTextField, isPlainTextareaField, pageFields, pageImageFieldForBackground, pageTextField, seoMetaFields };
|
package/package.json
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@stephenchenorg/astro-graphql",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "9.0.0",
|
|
5
|
+
"description": "Stephenchenorg Astro 前端 GraphQL 整合串接套件",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://stephenchenorg-astro.netlify.app",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/stephenchenorg/package.astro.git",
|
|
11
|
+
"directory": "packages/graphql"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"astro",
|
|
15
|
+
"graphql",
|
|
16
|
+
"api"
|
|
17
|
+
],
|
|
18
|
+
"exports": {
|
|
19
|
+
"./api": {
|
|
20
|
+
"types": "./dist/api/index.d.ts",
|
|
21
|
+
"import": "./dist/api/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./company-setting": {
|
|
24
|
+
"types": "./dist/company-setting/index.d.ts",
|
|
25
|
+
"import": "./dist/company-setting/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./image": {
|
|
28
|
+
"types": "./dist/image/index.d.ts",
|
|
29
|
+
"import": "./dist/image/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./image/components/Image.astro": "./dist/image/components/Image.astro",
|
|
32
|
+
"./image/components/ResponsiveImage.astro": "./dist/image/components/ResponsiveImage.astro",
|
|
33
|
+
"./page": {
|
|
34
|
+
"types": "./dist/page/index.d.ts",
|
|
35
|
+
"import": "./dist/page/index.js"
|
|
36
|
+
},
|
|
37
|
+
"./page/components/PageFieldRender.astro": "./dist/page/components/PageFieldRender.astro"
|
|
38
|
+
},
|
|
39
|
+
"typesVersions": {
|
|
40
|
+
"*": {
|
|
41
|
+
"*": [
|
|
42
|
+
"./dist/*"
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"files": [
|
|
47
|
+
"dist"
|
|
48
|
+
],
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=22"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"build": "tsdown",
|
|
57
|
+
"code-check": "astro check",
|
|
58
|
+
"prepack": "npm run build"
|
|
59
|
+
},
|
|
60
|
+
"peerDependencies": {
|
|
61
|
+
"@stephenchenorg/astro": "^9.0.0",
|
|
62
|
+
"astro": "^5.0.0"
|
|
63
|
+
},
|
|
64
|
+
"dependencies": {
|
|
65
|
+
"@graphql-typed-document-node/core": "^3.2.0",
|
|
66
|
+
"awesome-graphql-client": "^2.1.0",
|
|
67
|
+
"graphql": "^16.12.0",
|
|
68
|
+
"graphql-tag": "^2.12.6"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@astrojs/check": "^0.9.6",
|
|
72
|
+
"astro": "^5.16.4",
|
|
73
|
+
"tsdown": "^0.18.1",
|
|
74
|
+
"typescript": "^5.9.3"
|
|
75
|
+
}
|
|
76
|
+
}
|