@dxos/plugin-explorer 0.6.8-main.046e6cf
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 +8 -0
- package/README.md +3 -0
- package/dist/lib/browser/ExplorerArticle-IPAJQMAX.mjs +27 -0
- package/dist/lib/browser/ExplorerArticle-IPAJQMAX.mjs.map +7 -0
- package/dist/lib/browser/ExplorerMain-3KFXOEYO.mjs +33 -0
- package/dist/lib/browser/ExplorerMain-3KFXOEYO.mjs.map +7 -0
- package/dist/lib/browser/chunk-7YEM64IQ.mjs +473 -0
- package/dist/lib/browser/chunk-7YEM64IQ.mjs.map +7 -0
- package/dist/lib/browser/chunk-JIDPF2GF.mjs +27 -0
- package/dist/lib/browser/chunk-JIDPF2GF.mjs.map +7 -0
- package/dist/lib/browser/chunk-TL6ADY3P.mjs +21 -0
- package/dist/lib/browser/chunk-TL6ADY3P.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +38151 -0
- package/dist/lib/browser/index.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -0
- package/dist/lib/browser/meta.mjs +9 -0
- package/dist/lib/browser/meta.mjs.map +7 -0
- package/dist/lib/browser/types/index.mjs +10 -0
- package/dist/lib/browser/types/index.mjs.map +7 -0
- package/dist/lib/node/ExplorerArticle-PYOGBY3Z.cjs +53 -0
- package/dist/lib/node/ExplorerArticle-PYOGBY3Z.cjs.map +7 -0
- package/dist/lib/node/ExplorerMain-HGCLO5O4.cjs +59 -0
- package/dist/lib/node/ExplorerMain-HGCLO5O4.cjs.map +7 -0
- package/dist/lib/node/chunk-2GOPBQBC.cjs +494 -0
- package/dist/lib/node/chunk-2GOPBQBC.cjs.map +7 -0
- package/dist/lib/node/chunk-HYXFS3AG.cjs +45 -0
- package/dist/lib/node/chunk-HYXFS3AG.cjs.map +7 -0
- package/dist/lib/node/chunk-UJZYAOD2.cjs +54 -0
- package/dist/lib/node/chunk-UJZYAOD2.cjs.map +7 -0
- package/dist/lib/node/index.cjs +38158 -0
- package/dist/lib/node/index.cjs.map +7 -0
- package/dist/lib/node/meta.cjs +30 -0
- package/dist/lib/node/meta.cjs.map +7 -0
- package/dist/lib/node/meta.json +1 -0
- package/dist/lib/node/types/index.cjs +32 -0
- package/dist/lib/node/types/index.cjs.map +7 -0
- package/dist/types/src/ExplorerPlugin.d.ts +4 -0
- package/dist/types/src/ExplorerPlugin.d.ts.map +1 -0
- package/dist/types/src/components/Chart/Chart.d.ts +10 -0
- package/dist/types/src/components/Chart/Chart.d.ts.map +1 -0
- package/dist/types/src/components/Chart/Chart.stories.d.ts +11 -0
- package/dist/types/src/components/Chart/Chart.stories.d.ts.map +1 -0
- package/dist/types/src/components/Chart/index.d.ts +2 -0
- package/dist/types/src/components/Chart/index.d.ts.map +1 -0
- package/dist/types/src/components/ExplorerArticle.d.ts +7 -0
- package/dist/types/src/components/ExplorerArticle.d.ts.map +1 -0
- package/dist/types/src/components/ExplorerMain.d.ts +7 -0
- package/dist/types/src/components/ExplorerMain.d.ts.map +1 -0
- package/dist/types/src/components/Globe/Globe.d.ts +12 -0
- package/dist/types/src/components/Globe/Globe.d.ts.map +1 -0
- package/dist/types/src/components/Globe/Globe.stories.d.ts +12 -0
- package/dist/types/src/components/Globe/Globe.stories.d.ts.map +1 -0
- package/dist/types/src/components/Globe/index.d.ts +2 -0
- package/dist/types/src/components/Globe/index.d.ts.map +1 -0
- package/dist/types/src/components/Graph/Graph.d.ts +8 -0
- package/dist/types/src/components/Graph/Graph.d.ts.map +1 -0
- package/dist/types/src/components/Graph/Graph.stories.d.ts +14 -0
- package/dist/types/src/components/Graph/Graph.stories.d.ts.map +1 -0
- package/dist/types/src/components/Graph/graph-model.d.ts +33 -0
- package/dist/types/src/components/Graph/graph-model.d.ts.map +1 -0
- package/dist/types/src/components/Graph/index.d.ts +3 -0
- package/dist/types/src/components/Graph/index.d.ts.map +1 -0
- package/dist/types/src/components/Tree/Tree.d.ts +27 -0
- package/dist/types/src/components/Tree/Tree.d.ts.map +1 -0
- package/dist/types/src/components/Tree/Tree.stories.d.ts +29 -0
- package/dist/types/src/components/Tree/Tree.stories.d.ts.map +1 -0
- package/dist/types/src/components/Tree/index.d.ts +2 -0
- package/dist/types/src/components/Tree/index.d.ts.map +1 -0
- package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts +5 -0
- package/dist/types/src/components/Tree/layout/HierarchicalEdgeBundling.d.ts.map +1 -0
- package/dist/types/src/components/Tree/layout/RadialTree.d.ts +4 -0
- package/dist/types/src/components/Tree/layout/RadialTree.d.ts.map +1 -0
- package/dist/types/src/components/Tree/layout/TidyTree.d.ts +4 -0
- package/dist/types/src/components/Tree/layout/TidyTree.d.ts.map +1 -0
- package/dist/types/src/components/Tree/layout/index.d.ts +5 -0
- package/dist/types/src/components/Tree/layout/index.d.ts.map +1 -0
- package/dist/types/src/components/Tree/types.d.ts +8 -0
- package/dist/types/src/components/Tree/types.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +12 -0
- package/dist/types/src/components/index.d.ts.map +1 -0
- package/dist/types/src/components/plot.d.ts +12 -0
- package/dist/types/src/components/plot.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +5 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +15 -0
- package/dist/types/src/meta.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +12 -0
- package/dist/types/src/translations.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +3 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/types/types.d.ts +7 -0
- package/dist/types/src/types/types.d.ts.map +1 -0
- package/dist/types/src/types/view.d.ts +14 -0
- package/dist/types/src/types/view.d.ts.map +1 -0
- package/package.json +98 -0
- package/src/ExplorerPlugin.tsx +103 -0
- package/src/components/Chart/Chart.stories.tsx +46 -0
- package/src/components/Chart/Chart.tsx +54 -0
- package/src/components/Chart/index.ts +5 -0
- package/src/components/ExplorerArticle.tsx +28 -0
- package/src/components/ExplorerMain.tsx +34 -0
- package/src/components/Globe/Globe.stories.tsx +115 -0
- package/src/components/Globe/Globe.tsx +65 -0
- package/src/components/Globe/index.ts +5 -0
- package/src/components/Graph/Graph.stories.tsx +59 -0
- package/src/components/Graph/Graph.tsx +151 -0
- package/src/components/Graph/graph-model.ts +146 -0
- package/src/components/Graph/index.ts +7 -0
- package/src/components/Tree/Tree.stories.tsx +97 -0
- package/src/components/Tree/Tree.tsx +109 -0
- package/src/components/Tree/index.ts +5 -0
- package/src/components/Tree/layout/HierarchicalEdgeBundling.ts +164 -0
- package/src/components/Tree/layout/RadialTree.ts +96 -0
- package/src/components/Tree/layout/TidyTree.ts +102 -0
- package/src/components/Tree/layout/index.ts +9 -0
- package/src/components/Tree/types.ts +39 -0
- package/src/components/index.ts +14 -0
- package/src/components/plot.ts +15 -0
- package/src/index.ts +12 -0
- package/src/meta.tsx +19 -0
- package/src/translations.ts +18 -0
- package/src/types/index.ts +6 -0
- package/src/types/types.ts +27 -0
- package/src/types/view.ts +11 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { S } from '@dxos/echo-schema';
|
|
2
|
+
declare const ViewType_base: import("@dxos/echo-schema").AbstractTypedObject<{
|
|
3
|
+
type: string;
|
|
4
|
+
name?: string | undefined;
|
|
5
|
+
} & {
|
|
6
|
+
id: string;
|
|
7
|
+
}, S.Struct.Encoded<{
|
|
8
|
+
name: S.optional<typeof S.String>;
|
|
9
|
+
type: typeof S.String;
|
|
10
|
+
}>>;
|
|
11
|
+
export declare class ViewType extends ViewType_base {
|
|
12
|
+
}
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../../../src/types/view.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAe,MAAM,mBAAmB,CAAC;;;;;;;;;;AAGnD,qBAAa,QAAS,SAAQ,aAG5B;CAAG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dxos/plugin-explorer",
|
|
3
|
+
"version": "0.6.8-main.046e6cf",
|
|
4
|
+
"description": "Braneframe data visualization plugin",
|
|
5
|
+
"homepage": "https://dxos.org",
|
|
6
|
+
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "DXOS.org",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"browser": "./dist/lib/browser/index.mjs",
|
|
12
|
+
"node": {
|
|
13
|
+
"default": "./dist/lib/node/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"types": "./dist/types/src/index.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./meta": {
|
|
18
|
+
"browser": "./dist/lib/browser/meta.mjs",
|
|
19
|
+
"node": {
|
|
20
|
+
"default": "./dist/lib/node/meta.cjs"
|
|
21
|
+
},
|
|
22
|
+
"types": "./dist/types/src/meta.d.ts"
|
|
23
|
+
},
|
|
24
|
+
"./types": {
|
|
25
|
+
"browser": "./dist/lib/browser/types/index.mjs",
|
|
26
|
+
"node": {
|
|
27
|
+
"default": "./dist/lib/node/types/index.cjs"
|
|
28
|
+
},
|
|
29
|
+
"types": "./dist/types/src/types/index.d.ts"
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"types": "dist/types/src/index.d.ts",
|
|
33
|
+
"typesVersions": {
|
|
34
|
+
"*": {
|
|
35
|
+
"meta": [
|
|
36
|
+
"dist/types/src/meta.d.ts"
|
|
37
|
+
],
|
|
38
|
+
"types": [
|
|
39
|
+
"dist/types/src/types/index.d.ts"
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"files": [
|
|
44
|
+
"dist",
|
|
45
|
+
"src"
|
|
46
|
+
],
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@observablehq/plot": "^0.6.11",
|
|
49
|
+
"@preact/signals-core": "^1.6.0",
|
|
50
|
+
"d3": "^7.9.0",
|
|
51
|
+
"lodash.defaultsdeep": "^4.6.1",
|
|
52
|
+
"lodash.get": "^4.4.2",
|
|
53
|
+
"react-resize-detector": "^11.0.1",
|
|
54
|
+
"topojson-client": "^3.1.0",
|
|
55
|
+
"@dxos/async": "0.6.8-main.046e6cf",
|
|
56
|
+
"@dxos/app-framework": "0.6.8-main.046e6cf",
|
|
57
|
+
"@dxos/client": "0.6.8-main.046e6cf",
|
|
58
|
+
"@dxos/gem-core": "0.6.8-main.046e6cf",
|
|
59
|
+
"@dxos/gem-spore": "0.6.8-main.046e6cf",
|
|
60
|
+
"@dxos/echo-schema": "0.6.8-main.046e6cf",
|
|
61
|
+
"@dxos/log": "0.6.8-main.046e6cf",
|
|
62
|
+
"@dxos/plugin-client": "0.6.8-main.046e6cf",
|
|
63
|
+
"@dxos/plugin-graph": "0.6.8-main.046e6cf",
|
|
64
|
+
"@dxos/plugin-space": "0.6.8-main.046e6cf",
|
|
65
|
+
"@dxos/plugin-search": "0.6.8-main.046e6cf",
|
|
66
|
+
"@dxos/react-ui": "0.6.8-main.046e6cf",
|
|
67
|
+
"@dxos/react-client": "0.6.8-main.046e6cf"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@phosphor-icons/react": "^2.1.5",
|
|
71
|
+
"@types/d3": "^7.4.3",
|
|
72
|
+
"@types/d3-hierarchy": "^3.1.6",
|
|
73
|
+
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
74
|
+
"@types/lodash.get": "^4.4.7",
|
|
75
|
+
"@types/react": "~18.2.0",
|
|
76
|
+
"@types/react-dom": "~18.2.0",
|
|
77
|
+
"@types/topojson-client": "^3.1.3",
|
|
78
|
+
"react": "~18.2.0",
|
|
79
|
+
"react-dom": "~18.2.0",
|
|
80
|
+
"vite": "^5.3.4",
|
|
81
|
+
"@dxos/echo-generator": "0.6.8-main.046e6cf",
|
|
82
|
+
"@dxos/plugin-outliner": "0.6.8-main.046e6cf",
|
|
83
|
+
"@dxos/random": "0.6.8-main.046e6cf",
|
|
84
|
+
"@dxos/react-ui": "0.6.8-main.046e6cf",
|
|
85
|
+
"@dxos/react-ui-theme": "0.6.8-main.046e6cf",
|
|
86
|
+
"@dxos/storybook-utils": "0.6.8-main.046e6cf"
|
|
87
|
+
},
|
|
88
|
+
"optionalDependencies": {
|
|
89
|
+
"@phosphor-icons/react": "^2.1.5",
|
|
90
|
+
"react": "^18.0.0",
|
|
91
|
+
"react-dom": "^18.0.0",
|
|
92
|
+
"@dxos/react-ui": "0.6.8-main.046e6cf",
|
|
93
|
+
"@dxos/react-ui-theme": "0.6.8-main.046e6cf"
|
|
94
|
+
},
|
|
95
|
+
"publishConfig": {
|
|
96
|
+
"access": "public"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { Graph, type IconProps } from '@phosphor-icons/react';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
|
|
8
|
+
import { NavigationAction, parseIntentPlugin, resolvePlugin, type PluginDefinition } from '@dxos/app-framework';
|
|
9
|
+
import { parseClientPlugin } from '@dxos/plugin-client';
|
|
10
|
+
import { type ActionGroup, createExtension, isActionGroup } from '@dxos/plugin-graph';
|
|
11
|
+
import { SpaceAction } from '@dxos/plugin-space';
|
|
12
|
+
import { create } from '@dxos/react-client/echo';
|
|
13
|
+
|
|
14
|
+
import { ExplorerArticle, ExplorerMain } from './components';
|
|
15
|
+
import meta, { EXPLORER_PLUGIN } from './meta';
|
|
16
|
+
import translations from './translations';
|
|
17
|
+
import { ViewType } from './types';
|
|
18
|
+
import { ExplorerAction, type ExplorerPluginProvides } from './types';
|
|
19
|
+
|
|
20
|
+
export const ExplorerPlugin = (): PluginDefinition<ExplorerPluginProvides> => {
|
|
21
|
+
return {
|
|
22
|
+
meta,
|
|
23
|
+
provides: {
|
|
24
|
+
metadata: {
|
|
25
|
+
records: {
|
|
26
|
+
[ViewType.typename]: {
|
|
27
|
+
placeholder: ['object title placeholder', { ns: EXPLORER_PLUGIN }],
|
|
28
|
+
icon: (props: IconProps) => <Graph {...props} />,
|
|
29
|
+
iconSymbol: 'ph--graph--regular',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
translations,
|
|
34
|
+
echo: {
|
|
35
|
+
schema: [ViewType],
|
|
36
|
+
},
|
|
37
|
+
graph: {
|
|
38
|
+
builder: (plugins) => {
|
|
39
|
+
const client = resolvePlugin(plugins, parseClientPlugin)?.provides.client;
|
|
40
|
+
const dispatch = resolvePlugin(plugins, parseIntentPlugin)?.provides.intent.dispatch;
|
|
41
|
+
if (!client || !dispatch) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return createExtension({
|
|
46
|
+
id: ExplorerAction.CREATE,
|
|
47
|
+
filter: (node): node is ActionGroup => isActionGroup(node) && node.id.startsWith(SpaceAction.ADD_OBJECT),
|
|
48
|
+
actions: ({ node }) => {
|
|
49
|
+
const id = node.id.split('/').at(-1);
|
|
50
|
+
const [spaceId, objectId] = id?.split(':') ?? [];
|
|
51
|
+
const space = client.spaces.get().find((space) => space.id === spaceId);
|
|
52
|
+
const object = objectId && space?.db.getObjectById(objectId);
|
|
53
|
+
const target = objectId ? object : space;
|
|
54
|
+
if (!target) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return [
|
|
59
|
+
{
|
|
60
|
+
id: `${EXPLORER_PLUGIN}/create/${node.id}`,
|
|
61
|
+
data: async () => {
|
|
62
|
+
await dispatch([
|
|
63
|
+
{ plugin: EXPLORER_PLUGIN, action: ExplorerAction.CREATE },
|
|
64
|
+
{ action: SpaceAction.ADD_OBJECT, data: { target } },
|
|
65
|
+
{ action: NavigationAction.OPEN },
|
|
66
|
+
]);
|
|
67
|
+
},
|
|
68
|
+
properties: {
|
|
69
|
+
label: ['create object label', { ns: EXPLORER_PLUGIN }],
|
|
70
|
+
icon: (props: IconProps) => <Graph {...props} />,
|
|
71
|
+
iconSymbol: 'ph--graph--regular',
|
|
72
|
+
testId: 'explorerPlugin.createObject',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
surface: {
|
|
81
|
+
component: ({ data, role }) => {
|
|
82
|
+
switch (role) {
|
|
83
|
+
case 'main':
|
|
84
|
+
return data.active instanceof ViewType ? <ExplorerMain view={data.active} /> : null;
|
|
85
|
+
case 'article':
|
|
86
|
+
return data.object instanceof ViewType ? <ExplorerArticle view={data.object} /> : null;
|
|
87
|
+
default:
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
intent: {
|
|
93
|
+
resolver: (intent) => {
|
|
94
|
+
switch (intent.action) {
|
|
95
|
+
case ExplorerAction.CREATE: {
|
|
96
|
+
return { data: create(ViewType, { name: '', type: '' }) };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxosTheme';
|
|
6
|
+
|
|
7
|
+
import * as Plot from '@observablehq/plot';
|
|
8
|
+
import React, { useEffect, useState } from 'react';
|
|
9
|
+
|
|
10
|
+
import { ClientRepeater } from '@dxos/react-client/testing';
|
|
11
|
+
import { withFullscreen, withTheme } from '@dxos/storybook-utils';
|
|
12
|
+
|
|
13
|
+
import { Chart } from './Chart';
|
|
14
|
+
|
|
15
|
+
// TODO(burdon): Generate data with geo lat/lng.
|
|
16
|
+
// TODO(burdon): How to provide geo service via agent?
|
|
17
|
+
|
|
18
|
+
export default {
|
|
19
|
+
title: 'plugin-explorer/Chart',
|
|
20
|
+
component: Plot,
|
|
21
|
+
decorators: [withTheme, withFullscreen()],
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const Default = () => <ClientRepeater component={DefaultStory} />;
|
|
25
|
+
const DefaultStory = () => {
|
|
26
|
+
const [data, setData] = useState<{ cities: any }>();
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
setTimeout(async () => {
|
|
29
|
+
const cities = await (await fetch('/cities.json')).json();
|
|
30
|
+
setData({
|
|
31
|
+
cities,
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}, []);
|
|
35
|
+
|
|
36
|
+
if (!data) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const cities = data.cities.features.map((feature: any) => ({
|
|
41
|
+
x: feature.geometry.coordinates[0],
|
|
42
|
+
y: feature.geometry.coordinates[1],
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
return <Chart items={cities} accessor={(obj) => ({ x: obj.x, y: obj.y })} options={{ stroke: 'blue' }} />;
|
|
46
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Plot from '@observablehq/plot';
|
|
6
|
+
import { type DotOptions } from '@observablehq/plot';
|
|
7
|
+
import React, { useEffect } from 'react';
|
|
8
|
+
import { useResizeDetector } from 'react-resize-detector';
|
|
9
|
+
|
|
10
|
+
import { type Accessor, createAdapter, type Point } from '../plot';
|
|
11
|
+
|
|
12
|
+
const defaultOptions: DotOptions = {
|
|
13
|
+
r: 4,
|
|
14
|
+
stroke: 'gray',
|
|
15
|
+
fill: 'gray',
|
|
16
|
+
fillOpacity: 0.2,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type CharProps = {
|
|
20
|
+
items?: any[];
|
|
21
|
+
accessor?: Accessor<Point>;
|
|
22
|
+
options?: DotOptions;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const Chart = ({ items = [], accessor, options = defaultOptions }: CharProps) => {
|
|
26
|
+
const { ref: containerRef, width = 0, height = 0 } = useResizeDetector({ refreshRate: 200 });
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (!width || !height) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const plot = Plot.plot({
|
|
33
|
+
grid: true,
|
|
34
|
+
width,
|
|
35
|
+
height,
|
|
36
|
+
style: {
|
|
37
|
+
background: 'transparent',
|
|
38
|
+
},
|
|
39
|
+
marks: [
|
|
40
|
+
Plot.frame(),
|
|
41
|
+
Plot.dot(items, {
|
|
42
|
+
x: createAdapter('x', accessor),
|
|
43
|
+
y: createAdapter('y', accessor),
|
|
44
|
+
...options,
|
|
45
|
+
}),
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
containerRef.current!.append(plot);
|
|
50
|
+
return () => plot?.remove();
|
|
51
|
+
}, [items, width, height]);
|
|
52
|
+
|
|
53
|
+
return <div ref={containerRef} className='grow' />;
|
|
54
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { useGlobalSearch } from '@dxos/plugin-search';
|
|
8
|
+
import { getSpace } from '@dxos/react-client/echo';
|
|
9
|
+
|
|
10
|
+
import { Graph } from './Graph';
|
|
11
|
+
import { type ViewType } from '../types';
|
|
12
|
+
|
|
13
|
+
const ExplorerArticle = ({ view }: { view: ViewType }) => {
|
|
14
|
+
const space = getSpace(view);
|
|
15
|
+
const { match } = useGlobalSearch();
|
|
16
|
+
|
|
17
|
+
if (!space) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<div role='none' className='row-span-2 overflow-auto'>
|
|
23
|
+
<Graph space={space} match={match} />
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export default ExplorerArticle;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import React from 'react';
|
|
6
|
+
|
|
7
|
+
import { useGlobalSearch } from '@dxos/plugin-search';
|
|
8
|
+
import { getSpace } from '@dxos/react-client/echo';
|
|
9
|
+
import { Main } from '@dxos/react-ui';
|
|
10
|
+
import {
|
|
11
|
+
baseSurface,
|
|
12
|
+
topbarBlockPaddingStart,
|
|
13
|
+
fixedInsetFlexLayout,
|
|
14
|
+
bottombarBlockPaddingEnd,
|
|
15
|
+
} from '@dxos/react-ui-theme';
|
|
16
|
+
|
|
17
|
+
import { Graph } from './Graph';
|
|
18
|
+
import { type ViewType } from '../types';
|
|
19
|
+
|
|
20
|
+
const ExplorerMain = ({ view }: { view: ViewType }) => {
|
|
21
|
+
const space = getSpace(view);
|
|
22
|
+
const { match } = useGlobalSearch();
|
|
23
|
+
if (!space) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Main.Content classNames={[baseSurface, fixedInsetFlexLayout, topbarBlockPaddingStart, bottombarBlockPaddingEnd]}>
|
|
29
|
+
<Graph space={space} match={match} />
|
|
30
|
+
</Main.Content>
|
|
31
|
+
);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export default ExplorerMain;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxosTheme';
|
|
6
|
+
|
|
7
|
+
import * as Plot from '@observablehq/plot';
|
|
8
|
+
import * as d3 from 'd3';
|
|
9
|
+
import React, { useEffect, useState } from 'react';
|
|
10
|
+
import { useResizeDetector } from 'react-resize-detector';
|
|
11
|
+
import * as topojson from 'topojson-client';
|
|
12
|
+
|
|
13
|
+
import { ClientRepeater } from '@dxos/react-client/testing';
|
|
14
|
+
import { withFullscreen, withTheme } from '@dxos/storybook-utils';
|
|
15
|
+
|
|
16
|
+
import { Globe } from './Globe';
|
|
17
|
+
|
|
18
|
+
// TODO(burdon): Generate data with geo lat/lng.
|
|
19
|
+
// TODO(burdon): How to provide geo service via agent?
|
|
20
|
+
|
|
21
|
+
export default {
|
|
22
|
+
title: 'plugin-explorer/Globe',
|
|
23
|
+
component: Plot,
|
|
24
|
+
decorators: [withTheme, withFullscreen()],
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const Default = () => <ClientRepeater component={DefaultStory} createSpace />;
|
|
28
|
+
|
|
29
|
+
const DefaultStory = () => {
|
|
30
|
+
const [data, setData] = useState<{ world: any; cities: any }>();
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
setTimeout(async () => {
|
|
33
|
+
const world = await (await fetch('/countries-110m.json')).json();
|
|
34
|
+
const cities = await (await fetch('/cities.json')).json();
|
|
35
|
+
setData({
|
|
36
|
+
world,
|
|
37
|
+
cities,
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
if (!data) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const cities = data.cities.features.map((feature: any) => ({
|
|
47
|
+
lat: feature.geometry.coordinates[0],
|
|
48
|
+
lng: feature.geometry.coordinates[1],
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
return <Globe items={cities} />;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const Extended = () => <ClientRepeater component={ExtendedStory} createSpace />;
|
|
55
|
+
const ExtendedStory = () => {
|
|
56
|
+
const [data, setData] = useState<{ world: any; cities: any }>();
|
|
57
|
+
const { ref: containerRef, width = 0, height = 0 } = useResizeDetector({ refreshRate: 200 });
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
setTimeout(async () => {
|
|
60
|
+
const world = await (await fetch('/countries-110m.json')).json();
|
|
61
|
+
const cities = await (await fetch('/cities.json')).json();
|
|
62
|
+
setData({
|
|
63
|
+
world,
|
|
64
|
+
cities,
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}, []);
|
|
68
|
+
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (!data || !width || !height) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const land = topojson.feature(data.world, data.world.objects.land);
|
|
75
|
+
const cities = data.cities.features.map((feature: any) => ({
|
|
76
|
+
lat: feature.geometry.coordinates[0],
|
|
77
|
+
lng: feature.geometry.coordinates[1],
|
|
78
|
+
}));
|
|
79
|
+
|
|
80
|
+
const city = cities[0];
|
|
81
|
+
const circle = d3.geoCircle().center([city.lat, city.lng]).radius(16)();
|
|
82
|
+
|
|
83
|
+
// https://observablehq.com/plot/marks/geo
|
|
84
|
+
// https://observablehq.com/@observablehq/plot-earthquake-globe?intent=fork
|
|
85
|
+
const plot = Plot.plot({
|
|
86
|
+
// https://observablehq.com/plot/features/projections
|
|
87
|
+
projection: { type: 'orthographic', rotate: [-city.lat + 30, -30] },
|
|
88
|
+
// projection: { type: 'equirectangular', rotate: [-140, -30] },
|
|
89
|
+
width,
|
|
90
|
+
height,
|
|
91
|
+
style: {
|
|
92
|
+
background: 'transparent',
|
|
93
|
+
},
|
|
94
|
+
marks: [
|
|
95
|
+
Plot.sphere({ fill: 'lightblue', fillOpacity: 0.5 }),
|
|
96
|
+
Plot.geo(land, { fill: 'green', fillOpacity: 0.3 }),
|
|
97
|
+
Plot.graticule(),
|
|
98
|
+
Plot.geo(circle, { stroke: 'black', fill: 'darkblue', fillOpacity: 0.1, strokeWidth: 2 }),
|
|
99
|
+
Plot.dot(cities, {
|
|
100
|
+
x: 'lat',
|
|
101
|
+
y: 'lng',
|
|
102
|
+
r: 6,
|
|
103
|
+
stroke: 'red',
|
|
104
|
+
fill: 'red',
|
|
105
|
+
fillOpacity: 0.2,
|
|
106
|
+
}),
|
|
107
|
+
],
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
containerRef.current!.append(plot);
|
|
111
|
+
return () => plot?.remove();
|
|
112
|
+
}, [data, width, height]);
|
|
113
|
+
|
|
114
|
+
return <div ref={containerRef} className='grow p-8' />;
|
|
115
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type { DotOptions } from '@observablehq/plot';
|
|
6
|
+
import * as Plot from '@observablehq/plot';
|
|
7
|
+
import React, { useEffect } from 'react';
|
|
8
|
+
import { useResizeDetector } from 'react-resize-detector';
|
|
9
|
+
import * as topojson from 'topojson-client';
|
|
10
|
+
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
import world from '../../../public/countries-110m.json?json';
|
|
13
|
+
import { type Accessor, createAdapter, type GeoLocation } from '../plot';
|
|
14
|
+
|
|
15
|
+
const defaultOptions: DotOptions = {
|
|
16
|
+
r: 4,
|
|
17
|
+
fill: '#003300',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type GlobeProps = {
|
|
21
|
+
items?: any[];
|
|
22
|
+
accessor?: Accessor<GeoLocation>;
|
|
23
|
+
projection?: Plot.ProjectionName;
|
|
24
|
+
options?: DotOptions;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export const Globe = ({ items = [], accessor, projection = 'orthographic', options = defaultOptions }: GlobeProps) => {
|
|
28
|
+
const { ref: containerRef, width = 0, height = 0 } = useResizeDetector({ refreshRate: 200 });
|
|
29
|
+
const land = topojson.feature(world, world.objects.land);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!width || !height) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// https://observablehq.com/plot/marks/geo
|
|
37
|
+
// https://observablehq.com/@observablehq/plot-earthquake-globe?intent=fork
|
|
38
|
+
const plot = Plot.plot({
|
|
39
|
+
// https://observablehq.com/plot/features/projections
|
|
40
|
+
projection: { type: projection, rotate: [-100, -20] },
|
|
41
|
+
// projection: { type: 'equirectangular', rotate: [-140, -30] },
|
|
42
|
+
width,
|
|
43
|
+
height,
|
|
44
|
+
style: {
|
|
45
|
+
background: 'transparent',
|
|
46
|
+
},
|
|
47
|
+
// TODO(burdon): Create simple wrapper for Plot with good defaults.
|
|
48
|
+
marks: [
|
|
49
|
+
Plot.sphere({ fill: 'lightblue', fillOpacity: 0.5 }),
|
|
50
|
+
Plot.geo(land, { fill: 'darkgreen', fillOpacity: 0.5 }),
|
|
51
|
+
Plot.graticule(),
|
|
52
|
+
Plot.dot(items, {
|
|
53
|
+
x: createAdapter('lat', accessor),
|
|
54
|
+
y: createAdapter('lng', accessor),
|
|
55
|
+
...options,
|
|
56
|
+
}),
|
|
57
|
+
],
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
containerRef.current!.append(plot);
|
|
61
|
+
return () => plot?.remove();
|
|
62
|
+
}, [items, width, height]);
|
|
63
|
+
|
|
64
|
+
return <div ref={containerRef} className='grow p-4' />;
|
|
65
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import '@dxosTheme';
|
|
6
|
+
|
|
7
|
+
import React, { useEffect, useState } from 'react';
|
|
8
|
+
|
|
9
|
+
import { createSpaceObjectGenerator, TestSchemaType } from '@dxos/echo-generator';
|
|
10
|
+
import { create } from '@dxos/echo-schema';
|
|
11
|
+
import { faker } from '@dxos/random';
|
|
12
|
+
import { useClient } from '@dxos/react-client';
|
|
13
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
14
|
+
import { ClientRepeater } from '@dxos/react-client/testing';
|
|
15
|
+
import { withFullscreen, withTheme } from '@dxos/storybook-utils';
|
|
16
|
+
|
|
17
|
+
import { Graph } from './Graph';
|
|
18
|
+
import { ViewType } from '../../types';
|
|
19
|
+
|
|
20
|
+
faker.seed(1);
|
|
21
|
+
|
|
22
|
+
const Story = () => {
|
|
23
|
+
const client = useClient();
|
|
24
|
+
const [space, setSpace] = useState<Space>();
|
|
25
|
+
const [view, setView] = useState<ViewType>();
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
const space = client.spaces.default;
|
|
28
|
+
const generator = createSpaceObjectGenerator(space);
|
|
29
|
+
generator.addSchemas();
|
|
30
|
+
void generator
|
|
31
|
+
.createObjects({
|
|
32
|
+
[TestSchemaType.organization]: 20,
|
|
33
|
+
[TestSchemaType.contact]: 50,
|
|
34
|
+
})
|
|
35
|
+
.catch();
|
|
36
|
+
|
|
37
|
+
const view = space.db.add(create(ViewType, { name: '', type: '' }));
|
|
38
|
+
setSpace(space);
|
|
39
|
+
setView(view);
|
|
40
|
+
}, []);
|
|
41
|
+
|
|
42
|
+
if (!space || !view) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return <Graph space={space} />;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default {
|
|
50
|
+
title: 'plugin-explorer/Graph',
|
|
51
|
+
component: Graph,
|
|
52
|
+
render: () => <ClientRepeater component={Story} createSpace types={[ViewType]} />,
|
|
53
|
+
decorators: [withTheme, withFullscreen()],
|
|
54
|
+
parameters: {
|
|
55
|
+
layout: 'fullscreen',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const Default = {};
|