polen 0.0.4 → 0.0.6
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/README.md +47 -1
- package/build/app-template/components/ColumnView.d.ts +1 -1
- package/build/app-template/components/ColumnView.jsx +1 -1
- package/build/app-template/components/Link.d.ts +2 -1
- package/build/app-template/components/Link.jsx +7 -3
- package/build/app-template/components/RadixLink.d.ts +1 -1
- package/build/app-template/components/TypeAnnotation.jsx +1 -1
- package/build/app-template/components/TypeIndex.d.ts +6 -0
- package/build/app-template/components/TypeIndex.jsx +26 -0
- package/build/app-template/routes/home.d.ts +1 -0
- package/build/app-template/routes/home.jsx +1 -0
- package/build/app-template/routes/index.jsx +4 -2
- package/build/app-template/routes/layout.d.ts +1 -0
- package/build/app-template/routes/layout.jsx +23 -0
- package/build/app-template/routes/reference.jsx +5 -8
- package/build/app-template/routes/root.d.ts +0 -1
- package/build/app-template/routes/root.jsx +32 -8
- package/build/vite-plugin/_exports.js +14 -6
- package/build/vite-plugin/configurator/main.d.ts +14 -0
- package/build/vite-plugin/configurator/main.js +7 -0
- package/package.json +6 -10
package/README.md
CHANGED
|
@@ -5,5 +5,51 @@ A framework for delightful GraphQL developer portals ✨.
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```
|
|
8
|
-
npm add polen
|
|
8
|
+
npm add polen vite
|
|
9
9
|
```
|
|
10
|
+
|
|
11
|
+
Vite is a peer dependency of Polen.
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
The following shows minimal default usage.
|
|
16
|
+
|
|
17
|
+
1. Have a GraphQL schema file in the same directory that you run `vite`.
|
|
18
|
+
|
|
19
|
+
```graphql
|
|
20
|
+
type Query {
|
|
21
|
+
hello: String
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
2. Use Polen in your Vite config.
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
import { defineConfig } from 'vite'
|
|
29
|
+
import { Polen } from 'polen'
|
|
30
|
+
|
|
31
|
+
export default defineConfig({
|
|
32
|
+
plugins: [
|
|
33
|
+
Polen.VitePlugin({
|
|
34
|
+
// options here...
|
|
35
|
+
}),
|
|
36
|
+
],
|
|
37
|
+
})
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
3. Build your developer portal.
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
npx vite build --app
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
4. You now have a deployable developer portal. Try it locally
|
|
47
|
+
(http://localhost:5174):
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
node dist/entry.js
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Examples
|
|
54
|
+
|
|
55
|
+
You can find working examples in the [examples](./examples) directory.
|
|
@@ -2,7 +2,7 @@ import { Box, Flex, Heading } from '@radix-ui/themes';
|
|
|
2
2
|
import { Grafaid } from '../../lib/grafaid/index.js';
|
|
3
3
|
import { Link } from './Link.jsx';
|
|
4
4
|
import { entries } from '../../lib/prelude/main.js';
|
|
5
|
-
export const
|
|
5
|
+
export const TypeIndex = ({ schema }) => {
|
|
6
6
|
const kindMap = Grafaid.getKindMap(schema);
|
|
7
7
|
const sections = entries(kindMap.list);
|
|
8
8
|
return (<Flex direction="column" gap="6">
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { FC } from 'react';
|
|
2
|
+
import type { LinkPropsRadix } from './RadixLink.jsx';
|
|
2
3
|
import type { LinkProps as LinkPropsReactRouter } from 'react-router';
|
|
3
|
-
export declare const Link: FC<LinkPropsReactRouter>;
|
|
4
|
+
export declare const Link: FC<LinkPropsReactRouter & LinkPropsRadix>;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { LinkRadix } from './RadixLink.jsx';
|
|
2
2
|
import { Link as LinkReactRouter } from 'react-router';
|
|
3
|
-
export const Link = props =>
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export const Link = props => {
|
|
4
|
+
const { underline, color, m, mt, mb, ml, mr, my, mx } = props;
|
|
5
|
+
const radixProps = { underline, color, m, mt, mb, ml, mr, my, mx };
|
|
6
|
+
return (<LinkRadix asChild {...radixProps}>
|
|
7
|
+
<LinkReactRouter {...props}></LinkReactRouter>
|
|
8
|
+
</LinkRadix>);
|
|
9
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { Link as LinkRadix } from '@radix-ui/themes';
|
|
1
|
+
export { Link as LinkRadix, type LinkProps as LinkPropsRadix } from '@radix-ui/themes';
|
|
@@ -31,7 +31,7 @@ export const TypeAnnotation = ({ type }) => {
|
|
|
31
31
|
}
|
|
32
32
|
// If it's an expandable type (object or interface), make it a link
|
|
33
33
|
// if (Grafaid.isExpandableType(namedType)) {
|
|
34
|
-
return (<Link to=
|
|
34
|
+
return (<Link to={`/reference/${namedType.name}`}>
|
|
35
35
|
<Text color={isScalarType(namedType) ? `purple` : `blue`}>{namedType.name}</Text>
|
|
36
36
|
</Link>);
|
|
37
37
|
// For scalar and other non-expandable types, just render the name
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Box, Flex, Heading } from '@radix-ui/themes';
|
|
2
|
+
import { Grafaid } from '../../lib/grafaid/index.js';
|
|
3
|
+
import { Link } from './Link.jsx';
|
|
4
|
+
import { entries } from '../../lib/prelude/main.js';
|
|
5
|
+
export const TypeIndex = ({ schema }) => {
|
|
6
|
+
const kindMap = Grafaid.getKindMap(schema);
|
|
7
|
+
const sections = entries(kindMap.list);
|
|
8
|
+
return (<Flex direction="column" gap="6">
|
|
9
|
+
{sections.map(([title, types]) => <TypeSection key={title} title={title} types={types}/>)}
|
|
10
|
+
</Flex>);
|
|
11
|
+
};
|
|
12
|
+
const TypeSection = ({ title, types }) => {
|
|
13
|
+
return (<Box>
|
|
14
|
+
<Heading size="3">{title}</Heading>
|
|
15
|
+
<TypeList types={types}/>
|
|
16
|
+
</Box>);
|
|
17
|
+
};
|
|
18
|
+
const TypeList = ({ types }) => {
|
|
19
|
+
return ((<Box>
|
|
20
|
+
{types.map(type => (<Box key={type.name}>
|
|
21
|
+
<Link to={`/reference/${type.name}`}>
|
|
22
|
+
{type.name}
|
|
23
|
+
</Link>
|
|
24
|
+
</Box>))}
|
|
25
|
+
</Box>));
|
|
26
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { Link } from 'react-router';
|
|
2
1
|
import { createRouteIndex } from '../../lib/react-router-helpers.js';
|
|
3
|
-
|
|
2
|
+
import { Box } from '@radix-ui/themes';
|
|
3
|
+
const Component = () => {
|
|
4
|
+
return <Box>home todo</Box>;
|
|
5
|
+
};
|
|
4
6
|
export const index = createRouteIndex({
|
|
5
7
|
Component,
|
|
6
8
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const index: import("react-router").IndexRouteObject;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Link, Outlet } from 'react-router';
|
|
2
|
+
import { createRouteIndex } from '../../lib/react-router-helpers.js';
|
|
3
|
+
import { Box } from '@radix-ui/themes';
|
|
4
|
+
import { reference } from './reference.jsx';
|
|
5
|
+
const Component = () => {
|
|
6
|
+
return (<Box>
|
|
7
|
+
<Box>
|
|
8
|
+
<Box>
|
|
9
|
+
<Link to="/reference">Home</Link>
|
|
10
|
+
<Link to="/reference">Reference</Link>
|
|
11
|
+
</Box>
|
|
12
|
+
</Box>
|
|
13
|
+
<Box>
|
|
14
|
+
<Outlet />
|
|
15
|
+
</Box>
|
|
16
|
+
</Box>);
|
|
17
|
+
};
|
|
18
|
+
export const index = createRouteIndex({
|
|
19
|
+
Component,
|
|
20
|
+
children: [
|
|
21
|
+
reference,
|
|
22
|
+
],
|
|
23
|
+
});
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { buildASTSchema, parse } from 'graphql';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { TypeIndex } from '../components/TypeIndex.jsx';
|
|
3
|
+
import { Container, Flex } from '@radix-ui/themes';
|
|
4
4
|
import { Outlet, useLoaderData } from 'react-router';
|
|
5
|
-
// import { reference$type$field } from './reference.$type.$field.jsx'
|
|
6
5
|
import schemaFileContent from 'virtual:polen/assets/graphql-schema';
|
|
7
6
|
import { createRoute } from '../../lib/react-router-helpers.js';
|
|
8
7
|
import { reference$type } from './reference.$type.jsx';
|
|
9
8
|
const loader = () => {
|
|
10
9
|
const documentNode = parse(schemaFileContent);
|
|
11
|
-
// console.log(`running loader`, documentNode)
|
|
12
10
|
return {
|
|
13
11
|
documentNode,
|
|
14
12
|
};
|
|
@@ -17,10 +15,10 @@ const Component = () => {
|
|
|
17
15
|
const data = useLoaderData();
|
|
18
16
|
const schema = buildASTSchema(data.documentNode);
|
|
19
17
|
return (<Flex direction="row" align="start">
|
|
20
|
-
<
|
|
21
|
-
<
|
|
18
|
+
<TypeIndex schema={schema}/>
|
|
19
|
+
<Container>
|
|
22
20
|
<Outlet />
|
|
23
|
-
</
|
|
21
|
+
</Container>
|
|
24
22
|
</Flex>);
|
|
25
23
|
};
|
|
26
24
|
export const reference = createRoute({
|
|
@@ -29,6 +27,5 @@ export const reference = createRoute({
|
|
|
29
27
|
Component,
|
|
30
28
|
children: [
|
|
31
29
|
reference$type,
|
|
32
|
-
// reference$type$field,
|
|
33
30
|
],
|
|
34
31
|
});
|
|
@@ -1,29 +1,53 @@
|
|
|
1
|
+
import { Box, Text } from '@radix-ui/themes';
|
|
2
|
+
import { index } from './index.jsx';
|
|
3
|
+
import { Link as LinkReactRouter } from 'react-router';
|
|
4
|
+
import { GitHubLogoIcon } from '@radix-ui/react-icons';
|
|
5
|
+
import { Link } from '../components/Link.jsx';
|
|
1
6
|
import { Outlet, ScrollRestoration } from 'react-router';
|
|
2
|
-
import { Theme } from '@radix-ui/themes';
|
|
7
|
+
import { Flex, Theme } from '@radix-ui/themes';
|
|
3
8
|
import { createRoute } from '../../lib/react-router-helpers.js';
|
|
4
|
-
import { index } from './index.jsx';
|
|
5
9
|
import { reference } from './reference.jsx';
|
|
6
10
|
import radixStylesUrl from '@radix-ui/themes/styles.css?url';
|
|
7
11
|
import entryClientUrl from '../entry.client.jsx?url';
|
|
12
|
+
import templateVariables from 'virtual:polen/template/variables';
|
|
8
13
|
export const Component = () => {
|
|
9
14
|
return (<html lang="en">
|
|
10
15
|
<head>
|
|
11
16
|
<meta charSet="utf-8"/>
|
|
12
17
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
|
13
|
-
<title>
|
|
18
|
+
<title>{templateVariables.title}</title>
|
|
14
19
|
{import.meta.env.DEV && <link rel="stylesheet" href={radixStylesUrl}/>}
|
|
15
20
|
</head>
|
|
16
|
-
<body>
|
|
17
|
-
<
|
|
18
|
-
<Outlet />
|
|
19
|
-
</Theme>
|
|
21
|
+
<body style={{ margin: 0 }}>
|
|
22
|
+
<Layout />
|
|
20
23
|
<ScrollRestoration />
|
|
21
24
|
{import.meta.env.DEV && <script type="module" src={entryClientUrl}></script>}
|
|
22
25
|
</body>
|
|
23
26
|
</html>);
|
|
24
27
|
};
|
|
28
|
+
const Layout = () => {
|
|
29
|
+
return (<Theme asChild>
|
|
30
|
+
<Box m="8">
|
|
31
|
+
<Flex align="center" gap="8" pb="4" mb="8" style={{
|
|
32
|
+
borderBottom: `1px solid var(--gray-3)`,
|
|
33
|
+
}}>
|
|
34
|
+
<LinkReactRouter to="/" style={{ color: `inherit`, textDecoration: `none` }}>
|
|
35
|
+
<Flex align="center" gap="2">
|
|
36
|
+
<GitHubLogoIcon style={{ width: 30, height: 30 }}/>
|
|
37
|
+
<Text size="3" weight="medium">{templateVariables.title}</Text>
|
|
38
|
+
</Flex>
|
|
39
|
+
</LinkReactRouter>
|
|
40
|
+
<Flex direction="row" gap="4">
|
|
41
|
+
<Link color="gray" to="/reference">Reference</Link>
|
|
42
|
+
</Flex>
|
|
43
|
+
</Flex>
|
|
44
|
+
<Box>
|
|
45
|
+
<Outlet />
|
|
46
|
+
</Box>
|
|
47
|
+
</Box>
|
|
48
|
+
</Theme>);
|
|
49
|
+
};
|
|
25
50
|
export const root = createRoute({
|
|
26
|
-
id: `root`, // todo remove
|
|
27
51
|
path: `/`,
|
|
28
52
|
Component,
|
|
29
53
|
children: [
|
|
@@ -7,6 +7,7 @@ import { Build } from './build.js';
|
|
|
7
7
|
import { nodeAdapter as HonoDevServerNodeAdapter } from '@hono/vite-dev-server/node';
|
|
8
8
|
import HonoDevServer from '@hono/vite-dev-server';
|
|
9
9
|
const virtualIdentifierAssetGraphqlSchema = virtualIdentifier([`assets`, `graphql-schema`]);
|
|
10
|
+
const virtualIdentifierTemplateVariables = virtualIdentifier([`template`, `variables`]);
|
|
10
11
|
const codes = {
|
|
11
12
|
MODULE_LEVEL_DIRECTIVE: `MODULE_LEVEL_DIRECTIVE`,
|
|
12
13
|
CIRCULAR_DEPENDENCY: `CIRCULAR_DEPENDENCY`,
|
|
@@ -21,12 +22,19 @@ export const VitePlugin = (polenConfigInput) => {
|
|
|
21
22
|
}),
|
|
22
23
|
ReactVite(),
|
|
23
24
|
{
|
|
24
|
-
name: `polen-virtual
|
|
25
|
-
...Vite.VirtualIdentifier.toHooks(
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
name: `polen-virtual`,
|
|
26
|
+
...Vite.VirtualIdentifier.toHooks$FromMap(new Map([
|
|
27
|
+
[virtualIdentifierAssetGraphqlSchema, async () => {
|
|
28
|
+
const schema = await Fs.readFile(polenConfig.schema.path, `utf-8`);
|
|
29
|
+
const moduleContent = `export default ${JSON.stringify(schema)}`;
|
|
30
|
+
return moduleContent;
|
|
31
|
+
}],
|
|
32
|
+
// eslint-disable-next-line
|
|
33
|
+
[virtualIdentifierTemplateVariables, async () => {
|
|
34
|
+
const moduleContent = `export default ${JSON.stringify(polenConfig.templateVariables)}`;
|
|
35
|
+
return moduleContent;
|
|
36
|
+
}],
|
|
37
|
+
])),
|
|
30
38
|
},
|
|
31
39
|
{
|
|
32
40
|
name: `polen-build-client`,
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
export interface ConfigInput {
|
|
2
|
+
templateVariables?: {
|
|
3
|
+
/**
|
|
4
|
+
* Title of the app.
|
|
5
|
+
*
|
|
6
|
+
* Used in the navigation bar and in the title tag.
|
|
7
|
+
*
|
|
8
|
+
* @defaultValue `My Developer Portal`
|
|
9
|
+
*/
|
|
10
|
+
title?: string;
|
|
11
|
+
};
|
|
2
12
|
/**
|
|
3
13
|
* Path to the GraphQL schema file
|
|
4
14
|
*/
|
|
@@ -10,7 +20,11 @@ export interface ConfigInput {
|
|
|
10
20
|
*/
|
|
11
21
|
ssr?: boolean;
|
|
12
22
|
}
|
|
23
|
+
export interface TemplateVariables {
|
|
24
|
+
title: string;
|
|
25
|
+
}
|
|
13
26
|
export interface Config {
|
|
27
|
+
templateVariables: TemplateVariables;
|
|
14
28
|
mode: string;
|
|
15
29
|
schema: {
|
|
16
30
|
path: string;
|
|
@@ -3,6 +3,9 @@ const pathAppTemplateDir = Path.join(import.meta.dirname, `../../app-template`);
|
|
|
3
3
|
const workspaceDir = process.cwd();
|
|
4
4
|
const outDir = Path.join(workspaceDir, `dist`);
|
|
5
5
|
const configInputDefaults = {
|
|
6
|
+
templateVariables: {
|
|
7
|
+
title: `My Developer Portal`,
|
|
8
|
+
},
|
|
6
9
|
mode: `client`,
|
|
7
10
|
schema: {
|
|
8
11
|
path: Path.join(workspaceDir, `schema.graphql`),
|
|
@@ -29,6 +32,10 @@ export const normalizeInput = (configInput) => {
|
|
|
29
32
|
if (configInput?.ssr !== undefined) {
|
|
30
33
|
config.ssr.enabled = configInput.ssr;
|
|
31
34
|
}
|
|
35
|
+
config.templateVariables = {
|
|
36
|
+
...config.templateVariables,
|
|
37
|
+
...configInput?.templateVariables,
|
|
38
|
+
};
|
|
32
39
|
if (configInput?.schemaPath !== undefined) {
|
|
33
40
|
config.schema.path = Path.absolutify(configInput.schemaPath, config.paths.workspaceDir);
|
|
34
41
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "polen",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -16,25 +16,19 @@
|
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@hono/node-server": "^1.14.0",
|
|
19
|
-
"@hono/vite-build": "^1.5.0",
|
|
20
19
|
"@hono/vite-dev-server": "^0.19.0",
|
|
20
|
+
"@radix-ui/react-icons": "^1.3.2",
|
|
21
21
|
"@radix-ui/themes": "^3.2.1",
|
|
22
22
|
"consola": "^3.4.2",
|
|
23
23
|
"defu": "^6.1.4",
|
|
24
24
|
"es-toolkit": "^1.34.1",
|
|
25
25
|
"fuse.js": "^7.1.0",
|
|
26
|
-
"get-port-please": "^3.1.2",
|
|
27
26
|
"graphql": "^16.10.0",
|
|
28
27
|
"hono": "^4.7.5",
|
|
29
28
|
"marked": "^15.0.7",
|
|
30
29
|
"react": "^19.1.0",
|
|
31
30
|
"react-dom": "^19.1.0",
|
|
32
|
-
"react-
|
|
33
|
-
"react-markdown": "^10.1.0",
|
|
34
|
-
"react-router": "^7.5.0",
|
|
35
|
-
"rollup": "^4.39.0",
|
|
36
|
-
"tsx": "^4.19.3",
|
|
37
|
-
"zod": "^3.24.2"
|
|
31
|
+
"react-router": "^7.5.0"
|
|
38
32
|
},
|
|
39
33
|
"devDependencies": {
|
|
40
34
|
"@changesets/cli": "^2.28.1",
|
|
@@ -47,6 +41,7 @@
|
|
|
47
41
|
"@typescript-eslint/eslint-plugin": "^8.29.0",
|
|
48
42
|
"@typescript-eslint/parser": "^8.29.0",
|
|
49
43
|
"@vitejs/plugin-react": "^4.3.4",
|
|
44
|
+
"dripip": "^0.10.0",
|
|
50
45
|
"eslint": "^9.24.0",
|
|
51
46
|
"eslint-plugin-deprecation": "^3.0.0",
|
|
52
47
|
"eslint-plugin-only-warn": "^1.1.0",
|
|
@@ -56,6 +51,7 @@
|
|
|
56
51
|
"eslint-plugin-unused-imports": "^4.1.4",
|
|
57
52
|
"globals": "^16.0.0",
|
|
58
53
|
"publint": "^0.3.10",
|
|
54
|
+
"tsx": "^4.19.3",
|
|
59
55
|
"typescript": "^5.8.3",
|
|
60
56
|
"typescript-eslint": "^8.29.0",
|
|
61
57
|
"vite": "^6.2.5",
|
|
@@ -78,6 +74,6 @@
|
|
|
78
74
|
"check:lint": "eslint . --max-warnings 0",
|
|
79
75
|
"check:types": "tsc --noEmit",
|
|
80
76
|
"check:publint": "publint run --strict",
|
|
81
|
-
"release:version": "changeset version && git commit -am \"chore: release\""
|
|
77
|
+
"release:version": "changeset version && git commit -am \"chore: release\" && git push"
|
|
82
78
|
}
|
|
83
79
|
}
|