sanity-plugin-graph-view 3.0.0-v3-studio.6 → 3.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 +1 -1
- package/README.md +3 -36
- package/dist/index.cjs +359 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +6 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +366 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -64
- package/lib/index.esm.js +0 -2
- package/lib/index.esm.js.map +0 -1
- package/lib/index.js +0 -2
- package/lib/index.js.map +0 -1
- package/lib/src/index.d.ts +0 -9
- package/sanity.json +0 -8
- package/src/index.ts +0 -1
- package/src/plugin.tsx +0 -30
- package/src/tool/GraphView.tsx +0 -489
- package/src/tool/GraphViewIcon.tsx +0 -18
- package/src/tool/GraphViewStyle.tsx +0 -63
- package/src/tool/hooks.ts +0 -36
- package/src/tool/utils.ts +0 -51
- package/v2-incompatible.js +0 -11
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
> **NOTE**
|
|
2
|
-
>
|
|
3
|
-
> This is the **Sanity Studio v3 version** of sanity-plugin-graph-view.
|
|
4
|
-
>
|
|
5
|
-
> For the v2 version, please refer to the [v2-branch](https://github.com/sanity-io/sanity-plugin-graph-view).
|
|
6
|
-
|
|
7
1
|
<div align="center">
|
|
8
|
-
<img src="assets/sanity-logo.png" width="177" alt="Sanity" />
|
|
9
2
|
<h1>Graph View Plugin</h1>
|
|
10
3
|
<p>A tool for Sanity Studio to graph your content and see changes in real-time.</p>
|
|
11
4
|
<p><img src="assets/screengrab.gif" width="540" alt="Screengrab of the Graph tool" /></p>
|
|
12
5
|
</div>
|
|
13
6
|
|
|
7
|
+
|
|
14
8
|
Wonder how a visualization of your dataset will look? How many authors do you have? How many items have they worked on? And are currently working on! Edits and changes are shown in real-time!
|
|
15
9
|
|
|
16
10
|
**Explore your data with this plugin, seek out strange corners and data types, boldly go where you could not before!**
|
|
@@ -18,13 +12,7 @@ Wonder how a visualization of your dataset will look? How many authors do you ha
|
|
|
18
12
|
## Installation
|
|
19
13
|
|
|
20
14
|
```
|
|
21
|
-
npm install --save sanity-plugin-graph-view
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
or
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
yarn add sanity-plugin-graph-view@studio-v3
|
|
15
|
+
npm install --save sanity-plugin-graph-view
|
|
28
16
|
```
|
|
29
17
|
|
|
30
18
|
|
|
@@ -35,7 +23,7 @@ Add it as a plugin in sanity.config.ts (or .js):
|
|
|
35
23
|
```js
|
|
36
24
|
import { contentGraphView } from "sanity-plugin-graph-view";
|
|
37
25
|
|
|
38
|
-
export default
|
|
26
|
+
export default defineConfig({
|
|
39
27
|
// ...
|
|
40
28
|
plugins: [
|
|
41
29
|
contentGraphView({}),
|
|
@@ -90,27 +78,6 @@ contentGraphView({
|
|
|
90
78
|
})
|
|
91
79
|
```
|
|
92
80
|
|
|
93
|
-
## Get help in the Sanity Community
|
|
94
|
-
|
|
95
|
-
[](https://slack.sanity.io/)
|
|
96
|
-
|
|
97
|
-
Join [Sanity’s developer community](https://slack.sanity.io) or ping us [on twitter](https://twitter.com/sanity_io).
|
|
98
|
-
|
|
99
81
|
## License
|
|
100
82
|
|
|
101
83
|
MIT-licensed. See LICENSE.
|
|
102
|
-
|
|
103
|
-
## Develop & test
|
|
104
|
-
|
|
105
|
-
This plugin uses [@sanity/plugin-kit](https://github.com/sanity-io/plugin-kit)
|
|
106
|
-
with default configuration for build & watch scripts.
|
|
107
|
-
|
|
108
|
-
See [Testing a plugin in Sanity Studio](https://github.com/sanity-io/plugin-kit#testing-a-plugin-in-sanity-studio)
|
|
109
|
-
on how to run this plugin with hotreload in the studio.
|
|
110
|
-
|
|
111
|
-
### Release new version
|
|
112
|
-
|
|
113
|
-
Run ["CI & Release" workflow](https://github.com/sanity-io/sanity-plugin-graph-view/actions/workflows/main.yml).
|
|
114
|
-
Make sure to select the v3 branch and check "Release new version".
|
|
115
|
-
|
|
116
|
-
Semantic release will only release on configured branches, so it is safe to run release on any branch.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: !0 });
|
|
3
|
+
var jsxRuntime = require("react/jsx-runtime"), sanity = require("sanity"), router = require("sanity/router"), BezierEasing = require("bezier-easing"), deepEqual = require("deep-equal"), polished = require("polished"), react = require("react"), reactForceGraph = require("react-force-graph"), uuid = require("uuid"), color = require("@sanity/color"), ui = require("@sanity/ui"), styled = require("styled-components");
|
|
4
|
+
function _interopDefaultCompat(e) {
|
|
5
|
+
return e && typeof e == "object" && "default" in e ? e : { default: e };
|
|
6
|
+
}
|
|
7
|
+
var BezierEasing__default = /* @__PURE__ */ _interopDefaultCompat(BezierEasing), deepEqual__default = /* @__PURE__ */ _interopDefaultCompat(deepEqual), styled__default = /* @__PURE__ */ _interopDefaultCompat(styled);
|
|
8
|
+
const GraphRoot = styled__default.default.div`
|
|
9
|
+
font-family: ${({ theme }) => theme.fonts.text.family};
|
|
10
|
+
position: absolute;
|
|
11
|
+
top: 0;
|
|
12
|
+
left: 0;
|
|
13
|
+
width: 100%;
|
|
14
|
+
height: 100%;
|
|
15
|
+
background: ${color.black.hex};
|
|
16
|
+
`, GraphWrapper = styled__default.default.div`
|
|
17
|
+
position: relative;
|
|
18
|
+
width: 100%;
|
|
19
|
+
height: 100%;
|
|
20
|
+
`, HoverNode = styled__default.default.div`
|
|
21
|
+
font-family: ${({ theme }) => theme.fonts.text.family};
|
|
22
|
+
display: none;
|
|
23
|
+
position: absolute;
|
|
24
|
+
bottom: ${({ theme }) => theme.space[0]}px;
|
|
25
|
+
left: 50%;
|
|
26
|
+
transform: translate3d(-50%, 0, 0);
|
|
27
|
+
background: var(--component-bg);
|
|
28
|
+
border-radius: ${({ theme }) => theme.radius[2]}px;
|
|
29
|
+
padding: ${({ theme }) => theme.space[2]}px;
|
|
30
|
+
z-index: 1000;
|
|
31
|
+
|
|
32
|
+
&:empty {
|
|
33
|
+
display: none;
|
|
34
|
+
}
|
|
35
|
+
`, Legend = styled__default.default.div`
|
|
36
|
+
color: #ccc;
|
|
37
|
+
position: absolute;
|
|
38
|
+
top: ${({ theme }) => theme.space[4]}px;
|
|
39
|
+
left: ${({ theme }) => theme.space[4]}px;
|
|
40
|
+
|
|
41
|
+
& > div {
|
|
42
|
+
margin: 5px 0;
|
|
43
|
+
}
|
|
44
|
+
`, LegendRow = styled__default.default.div`
|
|
45
|
+
display: flex;
|
|
46
|
+
`, LegendBadge = styled__default.default.div`
|
|
47
|
+
width: 1.25em;
|
|
48
|
+
height: 1.25em;
|
|
49
|
+
background: currentColor;
|
|
50
|
+
border-radius: 50%;
|
|
51
|
+
margin-right: ${({ theme }) => theme.space[2]}px;
|
|
52
|
+
`;
|
|
53
|
+
function useListen(query, params, options, onUpdate, dependencies, client) {
|
|
54
|
+
react.useEffect(() => {
|
|
55
|
+
const subscription = client.listen(query, params, options).subscribe((update) => {
|
|
56
|
+
onUpdate(update);
|
|
57
|
+
});
|
|
58
|
+
return () => {
|
|
59
|
+
subscription.unsubscribe();
|
|
60
|
+
};
|
|
61
|
+
}, [...dependencies, client]);
|
|
62
|
+
}
|
|
63
|
+
function useFetchDocuments(query, onFetch, dependencies, client) {
|
|
64
|
+
react.useEffect(() => {
|
|
65
|
+
client.fetch(query).then((result) => {
|
|
66
|
+
onFetch(result);
|
|
67
|
+
});
|
|
68
|
+
}, [...dependencies, client]);
|
|
69
|
+
}
|
|
70
|
+
function sizeOf(value) {
|
|
71
|
+
return value === null ? 0 : typeof value == "object" ? Object.entries(value).reduce((total, [k, v]) => total + sizeOf(k) + sizeOf(v), 0) : Array.isArray(value) ? Object.entries(value).reduce((total, v) => total + sizeOf(v), 0) : typeof value == "string" ? value.length : 1;
|
|
72
|
+
}
|
|
73
|
+
function loadImage(url, w, h) {
|
|
74
|
+
return new Promise((resolve) => {
|
|
75
|
+
const img = new Image(w, h);
|
|
76
|
+
img.onload = () => {
|
|
77
|
+
resolve(img);
|
|
78
|
+
}, img.onerror = (event) => {
|
|
79
|
+
console.log("Image error", event), resolve(null);
|
|
80
|
+
}, img.src = url;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function sortBy(array, f) {
|
|
84
|
+
return array.sort((a, b) => {
|
|
85
|
+
const va = f(a), vb = f(b);
|
|
86
|
+
return va < vb ? -1 : va > vb ? 1 : 0;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
function truncate(s, limit) {
|
|
90
|
+
return s.length > limit ? `${s.substring(0, limit)}\u2026` : s;
|
|
91
|
+
}
|
|
92
|
+
const DEFAULT_QUERY = `
|
|
93
|
+
*[
|
|
94
|
+
!(_id in path("_.*")) &&
|
|
95
|
+
!(_type match "system.*") &&
|
|
96
|
+
!(_type match "sanity.*")
|
|
97
|
+
]
|
|
98
|
+
`, fadeEasing = BezierEasing__default.default(0, 0.9, 1, 1), softEasing = BezierEasing__default.default(0.25, 0.1, 0, 1), idleTimeout = 1e4, imageSize = 40;
|
|
99
|
+
function getTopDocTypes(counts) {
|
|
100
|
+
return sortBy(Object.keys(counts), (docType) => counts[docType] || 0).reverse().slice(0, 10);
|
|
101
|
+
}
|
|
102
|
+
function formatDocType(docType) {
|
|
103
|
+
return (docType.substring(0, 1).toUpperCase() + docType.substring(1)).replace(/\./g, " ").replace(/[A-Z]/g, " $&").trim();
|
|
104
|
+
}
|
|
105
|
+
function getDocTypeCounts(docs) {
|
|
106
|
+
const types = {};
|
|
107
|
+
for (const doc of docs)
|
|
108
|
+
types[doc._type] = (types[doc._type] || 0) + 1;
|
|
109
|
+
return types;
|
|
110
|
+
}
|
|
111
|
+
function labelFor(doc) {
|
|
112
|
+
return `${doc.title || doc.name || doc._id}`.trim();
|
|
113
|
+
}
|
|
114
|
+
function valueFor(doc, maxSize) {
|
|
115
|
+
return 5 + 100 * (sizeOf(doc) / maxSize);
|
|
116
|
+
}
|
|
117
|
+
function findRefs(obj, dest = []) {
|
|
118
|
+
if (obj !== null) {
|
|
119
|
+
if (typeof obj == "object")
|
|
120
|
+
for (const [k, v] of Object.entries(obj))
|
|
121
|
+
k === "_ref" && typeof v == "string" && v.length > 0 && dest.push(stripDraftId(v)), findRefs(v, dest);
|
|
122
|
+
else if (Array.isArray(obj))
|
|
123
|
+
for (const v of obj)
|
|
124
|
+
findRefs(v, dest);
|
|
125
|
+
}
|
|
126
|
+
return dest;
|
|
127
|
+
}
|
|
128
|
+
function stripDraftId(id) {
|
|
129
|
+
return id.replace(/^drafts\./, "");
|
|
130
|
+
}
|
|
131
|
+
function deduplicateDrafts(docs) {
|
|
132
|
+
const deduped = {};
|
|
133
|
+
for (const doc of docs)
|
|
134
|
+
doc._id.startsWith("drafts.") || (deduped[doc._id] = doc);
|
|
135
|
+
for (const doc of docs)
|
|
136
|
+
if (doc._id.startsWith("drafts.")) {
|
|
137
|
+
const id = stripDraftId(doc._id);
|
|
138
|
+
deduped[id] = Object.assign(doc, { _id: id });
|
|
139
|
+
}
|
|
140
|
+
return Object.values(deduped);
|
|
141
|
+
}
|
|
142
|
+
class Users {
|
|
143
|
+
_users = [];
|
|
144
|
+
async getById(id, client) {
|
|
145
|
+
let user = this._users.find((u) => u._id === id);
|
|
146
|
+
return user || (user = await client.users.getById(id), this._users.push(user), user.image = await loadImage(
|
|
147
|
+
user.imageUrl || "https://raw.githubusercontent.com/sanity-io/sanity-plugin-graph-view/main/assets/head-silhouette.jpg",
|
|
148
|
+
imageSize,
|
|
149
|
+
imageSize
|
|
150
|
+
)), user;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
class Session {
|
|
154
|
+
id = null;
|
|
155
|
+
user = null;
|
|
156
|
+
doc = null;
|
|
157
|
+
lastActive = 0;
|
|
158
|
+
startTime = 0;
|
|
159
|
+
angle = 0;
|
|
160
|
+
}
|
|
161
|
+
class GraphData {
|
|
162
|
+
sessions = [];
|
|
163
|
+
data;
|
|
164
|
+
constructor(docs = []) {
|
|
165
|
+
const docsById = {};
|
|
166
|
+
for (const doc of docs)
|
|
167
|
+
docsById[doc._id] = doc;
|
|
168
|
+
this.data = {
|
|
169
|
+
nodes: docs.map((d) => Object.assign({ id: d._id, type: "document", doc: d })),
|
|
170
|
+
links: docs.flatMap((doc) => findRefs(doc).map((ref) => ({ source: doc._id, target: ref }))).filter((link) => docsById[link.source] && docsById[link.target])
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
setSession(user, docNode) {
|
|
174
|
+
let session = this.sessions.find((s) => s.user.id === user.id && s.doc?._id === docNode.doc._id);
|
|
175
|
+
session || (session = new Session(), session.id = uuid.v4(), session.user = user, session.startTime = Date.now(), session.doc = docNode.doc, session.angle = Math.random() * 2 * Math.PI, this.sessions.push(session)), session.lastActive = Date.now();
|
|
176
|
+
}
|
|
177
|
+
reapSessions() {
|
|
178
|
+
for (let i = 0; i < this.sessions.length; i++) {
|
|
179
|
+
const session = this.sessions[i];
|
|
180
|
+
Date.now() - session.lastActive > idleTimeout && (this.sessions = [...this.sessions.slice(0, i), ...this.sessions.slice(i + 1)], i--);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
clone() {
|
|
184
|
+
const copy = new GraphData();
|
|
185
|
+
return Object.assign(copy, this), copy.data = {
|
|
186
|
+
nodes: [...this.data.nodes],
|
|
187
|
+
links: [...this.data.links]
|
|
188
|
+
}, copy;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const users = new Users();
|
|
192
|
+
function GraphView(props) {
|
|
193
|
+
const query = props.query || DEFAULT_QUERY, apiVersion = props.apiVersion ?? "2022-09-01", userColorManager = sanity.useUserColorManager(), [maxSize, setMaxSize] = react.useState(0), [hoverNode, setHoverNode] = react.useState(null), [documents, setDocuments] = react.useState([]), [docTypes, setDocTypes] = react.useState({}), [graph, setGraph] = react.useState(() => new GraphData()), router$1 = router.useRouter(), client = sanity.useClient({ apiVersion }), fetchCallback = react.useCallback((_docs) => {
|
|
194
|
+
const docs = deduplicateDrafts(_docs);
|
|
195
|
+
setMaxSize(Math.max(...docs.map(sizeOf))), setDocuments(docs), setDocTypes(getDocTypeCounts(docs)), setGraph(new GraphData(docs));
|
|
196
|
+
}, []), listenCallback = react.useCallback(
|
|
197
|
+
async (update) => {
|
|
198
|
+
const doc = update.result;
|
|
199
|
+
if (doc) {
|
|
200
|
+
doc._id = stripDraftId(doc._id);
|
|
201
|
+
const docsById = {};
|
|
202
|
+
for (const d of documents)
|
|
203
|
+
docsById[d._id] = d;
|
|
204
|
+
let oldDoc;
|
|
205
|
+
const docs = [...documents], idx = documents.findIndex((d) => d._id === doc._id);
|
|
206
|
+
idx >= 0 ? (oldDoc = docs[idx], docs[idx] = doc) : docs.push(doc), setDocuments(docs), setDocTypes(getDocTypeCounts(docs)), setMaxSize(Math.max(...docs.map(sizeOf)));
|
|
207
|
+
const newGraph = graph.clone(), oldRefs = findRefs(oldDoc || {}).filter(
|
|
208
|
+
(id) => id === doc._id || docsById[id] !== null
|
|
209
|
+
), newRefs = findRefs(doc).filter((id) => id === doc._id || docsById[id] !== null);
|
|
210
|
+
let graphChanged = !deepEqual__default.default(oldRefs, newRefs);
|
|
211
|
+
graphChanged && (newGraph.data.links = newGraph.data.links.filter((l) => l.source.id !== doc._id).concat(newRefs.map((ref) => ({ source: doc._id, target: ref }))));
|
|
212
|
+
let docNode;
|
|
213
|
+
const nodeIdx = graph.data.nodes.findIndex((n) => n.doc && n.doc._id === doc._id);
|
|
214
|
+
nodeIdx >= 0 ? (docNode = graph.data.nodes[nodeIdx], docNode.doc = doc) : (docNode = { id: doc._id, type: "document", doc }, newGraph.data.nodes.push(docNode), graphChanged = !0), graphChanged && setGraph(newGraph);
|
|
215
|
+
const user = await users.getById(update.identity, client);
|
|
216
|
+
graph.setSession(user, docNode);
|
|
217
|
+
} else if (update.transition === "disappear") {
|
|
218
|
+
const docId = stripDraftId(update.documentId), docs = documents.filter((d) => d._id !== docId);
|
|
219
|
+
setDocuments(docs), setDocTypes(getDocTypeCounts(docs)), setMaxSize(Math.max(...docs.map(sizeOf)));
|
|
220
|
+
const newGraph = graph.clone();
|
|
221
|
+
newGraph.data.links = newGraph.data.links.filter(
|
|
222
|
+
(l) => l.source.id !== docId && l.target.id !== docId
|
|
223
|
+
), newGraph.data.nodes = newGraph.data.nodes.filter((n) => n.id !== docId), setGraph(newGraph);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
[documents, graph, client]
|
|
227
|
+
);
|
|
228
|
+
useFetchDocuments(query, fetchCallback, [], client), useListen(query, {}, {}, listenCallback, [documents, graph], client), react.useEffect(() => {
|
|
229
|
+
const interval = setInterval(() => graph.reapSessions(), 1e3);
|
|
230
|
+
return () => clearInterval(interval);
|
|
231
|
+
}, [graph]);
|
|
232
|
+
const theme = ui.useTheme().sanity;
|
|
233
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GraphWrapper, { theme, children: /* @__PURE__ */ jsxRuntime.jsxs(GraphRoot, { theme, children: [
|
|
234
|
+
/* @__PURE__ */ jsxRuntime.jsx(Legend, { theme, children: getTopDocTypes(docTypes).map((docType) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
235
|
+
LegendRow,
|
|
236
|
+
{
|
|
237
|
+
className: "legend__row",
|
|
238
|
+
style: { color: getDocTypeColor(docType).fill },
|
|
239
|
+
children: [
|
|
240
|
+
/* @__PURE__ */ jsxRuntime.jsx(LegendBadge, { theme }),
|
|
241
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { children: formatDocType(docType) })
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
docType
|
|
245
|
+
)) }),
|
|
246
|
+
hoverNode && /* @__PURE__ */ jsxRuntime.jsx(HoverNode, { theme, children: labelFor(hoverNode.doc) }),
|
|
247
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
248
|
+
reactForceGraph.ForceGraph2D,
|
|
249
|
+
{
|
|
250
|
+
graphData: graph.data,
|
|
251
|
+
nodeAutoColorBy: "group",
|
|
252
|
+
enableNodeDrag: !1,
|
|
253
|
+
onNodeHover: (node) => setHoverNode(node),
|
|
254
|
+
onNodeClick: (node) => {
|
|
255
|
+
router$1.navigateIntent("edit", { id: node.doc._id, documentType: node.doc._type });
|
|
256
|
+
},
|
|
257
|
+
linkColor: () => polished.rgba(color.gray[500].hex, 0.25),
|
|
258
|
+
nodeLabel: () => "",
|
|
259
|
+
nodeRelSize: 1,
|
|
260
|
+
nodeVal: (node) => valueFor(node.doc, maxSize),
|
|
261
|
+
onRenderFramePost: (ctx, globalScale) => {
|
|
262
|
+
for (const session of graph.sessions) {
|
|
263
|
+
const node = graph.data.nodes.find(
|
|
264
|
+
(n) => n.doc && n.doc._id === session?.doc?._id
|
|
265
|
+
);
|
|
266
|
+
if (node) {
|
|
267
|
+
const idleFactorRange = idleTimeout, angle = session.angle, radius = Math.sqrt(valueFor(node.doc, maxSize)), image = session.user.image, userColor = userColorManager.get(session.user.displayName).tints[400].hex, distance = radius * globalScale + 40, imgW = image ? image.width : 0, imgH = image ? image.height : 0, x = node.x + Math.sin(angle) * distance / globalScale, y = node.y + Math.cos(angle) * distance / globalScale;
|
|
268
|
+
ctx.save();
|
|
269
|
+
try {
|
|
270
|
+
if (ctx.globalAlpha = fadeEasing(
|
|
271
|
+
1 - Math.min(idleFactorRange, Date.now() - session.lastActive) / idleFactorRange
|
|
272
|
+
), ctx.font = `bold ${Math.round(12 / globalScale)}px sans-serif`, ctx.beginPath(), ctx.strokeStyle = polished.rgba(color.white.hex, 1), ctx.lineWidth = 2 / globalScale, ctx.moveTo(
|
|
273
|
+
node.x + Math.sin(angle) * (distance - imgW / 2) / globalScale,
|
|
274
|
+
node.y + Math.cos(angle) * (distance - imgH / 2) / globalScale
|
|
275
|
+
), ctx.lineTo(node.x + Math.sin(angle) * radius, node.y + Math.cos(angle) * radius), ctx.stroke(), ctx.beginPath(), ctx.strokeStyle = polished.rgba(color.white.hex, 1), ctx.lineWidth = 2 / globalScale, ctx.arc(node.x, node.y, radius, 0, 2 * Math.PI, !1), ctx.stroke(), image) {
|
|
276
|
+
ctx.save();
|
|
277
|
+
try {
|
|
278
|
+
const f = softEasing(
|
|
279
|
+
Math.max(0, (700 - (Date.now() - session.startTime)) / 700)
|
|
280
|
+
);
|
|
281
|
+
f > 0 && (ctx.beginPath(), ctx.fillStyle = polished.rgba(userColor, f), ctx.arc(x, y, (imgW / 2 + 10) / globalScale, 0, 2 * Math.PI, !1), ctx.fill()), ctx.beginPath(), ctx.fillStyle = polished.rgba(color.white.hex, 1), ctx.arc(x, y, imgW / globalScale / 2, 0, 2 * Math.PI, !1), ctx.clip(), ctx.drawImage(
|
|
282
|
+
image,
|
|
283
|
+
x - imgW / globalScale / 2,
|
|
284
|
+
y - imgH / globalScale / 2,
|
|
285
|
+
imgW / globalScale,
|
|
286
|
+
imgH / globalScale
|
|
287
|
+
), ctx.strokeStyle = color.black.hex, ctx.lineWidth = 6 / globalScale, ctx.stroke(), ctx.strokeStyle = userColor, ctx.lineWidth = 4 / globalScale, ctx.stroke();
|
|
288
|
+
} finally {
|
|
289
|
+
ctx.restore();
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
ctx.beginPath(), ctx.strokeStyle = polished.rgba(color.black.hex, 1), ctx.lineWidth = 0.5 / globalScale, ctx.arc(x, y, imgW / globalScale / 2, 0, 2 * Math.PI, !1), ctx.stroke();
|
|
293
|
+
const above = angle >= Math.PI / 2 && angle < Math.PI * 1.5, textY = above ? y - (imgH / 2 + 5) / globalScale : y + (imgH / 2 + 5) / globalScale;
|
|
294
|
+
ctx.fillStyle = polished.rgba(color.white.hex, 1), ctx.textAlign = "center", ctx.textBaseline = above ? "bottom" : "top", ctx.fillText(session.user.displayName, x, textY);
|
|
295
|
+
} finally {
|
|
296
|
+
ctx.restore();
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
nodeCanvasObject: (node, ctx, globalScale) => {
|
|
302
|
+
switch (node.type) {
|
|
303
|
+
case "document": {
|
|
304
|
+
const nodeColor = getDocTypeColor(node.doc._type), radius = Math.sqrt(valueFor(node.doc, maxSize)), fontSize = Math.min(100, 10 / globalScale);
|
|
305
|
+
if (ctx.beginPath(), ctx.fillStyle = hoverNode !== null && node.doc._id === hoverNode.doc._id ? polished.rgba(color.gray[500].hex, 0.8) : nodeColor.fill, ctx.strokeStyle = nodeColor.border, ctx.lineWidth = 0.5, ctx.arc(node.x, node.y, radius, 0, 2 * Math.PI, !1), ctx.stroke(), ctx.fill(), radius * globalScale > 10) {
|
|
306
|
+
ctx.font = `${fontSize}px sans-serif`;
|
|
307
|
+
const w = radius * 2 + 30 / globalScale;
|
|
308
|
+
for (let len = 50; len >= 5; len /= 1.2) {
|
|
309
|
+
const label = truncate(labelFor(node.doc), Math.round(len));
|
|
310
|
+
if (ctx.measureText(label).width < w) {
|
|
311
|
+
ctx.textAlign = "center", ctx.textBaseline = "top", ctx.strokeStyle = polished.rgba(color.black.hex, 0.5), ctx.lineWidth = 2 / globalScale, ctx.strokeText(label, node.x, node.y + radius + 5 / globalScale), ctx.fillText(label, node.x, node.y + radius + 5 / globalScale);
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
linkCanvasObject: (link, ctx, globalScale) => {
|
|
320
|
+
ctx.beginPath(), ctx.strokeStyle = polished.rgba(color.gray[500].hex, 0.125), ctx.lineWidth = 2 / globalScale, ctx.moveTo(link.source.x, link.source.y), ctx.lineTo(link.target.x, link.target.y), ctx.stroke();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
)
|
|
324
|
+
] }) });
|
|
325
|
+
}
|
|
326
|
+
const colorCache = {};
|
|
327
|
+
let typeColorNum = 0;
|
|
328
|
+
function getDocTypeColor(docType) {
|
|
329
|
+
if (colorCache[docType])
|
|
330
|
+
return colorCache[docType];
|
|
331
|
+
const hue = color.COLOR_HUES[typeColorNum % color.COLOR_HUES.length];
|
|
332
|
+
return typeColorNum += 1, colorCache[docType] = {
|
|
333
|
+
fill: color.hues[hue][400].hex,
|
|
334
|
+
border: polished.rgba(color.black.hex, 0.5)
|
|
335
|
+
}, colorCache[docType];
|
|
336
|
+
}
|
|
337
|
+
const GraphViewIcon = () => /* @__PURE__ */ jsxRuntime.jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "1em", height: "1em", viewBox: "0 0 46.063 46.063", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
338
|
+
"path",
|
|
339
|
+
{
|
|
340
|
+
fill: "currentColor",
|
|
341
|
+
d: "M18.022 38.676v2.813h-1.21q-4.864 0-6.525-1.447-1.64-1.445-1.64-5.762v-4.666q0-2.95-1.055-4.083-1.055-1.13-3.828-1.13h-1.19v-2.794h1.19q2.793 0 3.828-1.114 1.055-1.132 1.055-4.043V11.76q0-4.316 1.64-5.742 1.66-1.446 6.524-1.446h1.212v2.793h-1.328q-2.754 0-3.594.86-.84.86-.84 3.613v4.844q0 3.066-.898 4.453-.88 1.387-3.028 1.875 2.168.527 3.047 1.914.88 1.387.88 4.434v4.843q0 2.754.84 3.614.84.86 3.594.86h1.328zM28.04 38.676h1.368q2.735 0 3.555-.84.84-.84.84-3.633V29.36q0-3.047.88-4.434.878-1.387 3.046-1.914-2.17-.488-3.048-1.875-.88-1.387-.88-4.453V11.84q0-2.773-.84-3.613-.82-.86-3.554-.86H28.04V4.574h1.232q4.863 0 6.484 1.446 1.64 1.426 1.64 5.742v4.687q0 2.91 1.055 4.042 1.056 1.114 3.83 1.114h1.21V24.4h-1.21q-2.774 0-3.83 1.13-1.053 1.134-1.053 4.084v4.667q0 4.318-1.64 5.763-1.622 1.446-6.485 1.446h-1.23v-2.814z"
|
|
342
|
+
}
|
|
343
|
+
) }), contentGraphView = sanity.definePlugin((config = {}) => ({
|
|
344
|
+
name: "@sanity/content-graph-view",
|
|
345
|
+
tools: (prev) => [
|
|
346
|
+
...prev,
|
|
347
|
+
{
|
|
348
|
+
name: "graph-your-content",
|
|
349
|
+
title: "Graph",
|
|
350
|
+
icon: GraphViewIcon,
|
|
351
|
+
component: function() {
|
|
352
|
+
return /* @__PURE__ */ jsxRuntime.jsx(GraphView, { ...config });
|
|
353
|
+
},
|
|
354
|
+
router: router.route.create("/:selectedDocumentId")
|
|
355
|
+
}
|
|
356
|
+
]
|
|
357
|
+
}));
|
|
358
|
+
exports.contentGraphView = contentGraphView;
|
|
359
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/tool/GraphViewStyle.tsx","../src/tool/hooks.ts","../src/tool/utils.ts","../src/tool/GraphView.tsx","../src/tool/GraphViewIcon.tsx","../src/plugin.tsx"],"sourcesContent":["import React, {type PropsWithChildren} from 'react'\nimport styled from 'styled-components'\n\nimport type {Theme} from '@sanity/ui'\n\nimport {black} from '@sanity/color'\n\ntype Style = PropsWithChildren<{theme: SanityTheme}>\ntype SanityTheme = Theme['sanity']\n\nexport const GraphRoot: React.FC<Style> = styled.div`\n font-family: ${({theme}: Style) => theme.fonts.text.family};\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: ${black.hex};\n`\n\nexport const GraphWrapper: React.FC<Style> = styled.div`\n position: relative;\n width: 100%;\n height: 100%;\n` as React.FC<Style>\n\nexport const HoverNode: React.FC<Style> = styled.div`\n font-family: ${({theme}: Style) => theme.fonts.text.family};\n display: none;\n position: absolute;\n bottom: ${({theme}: Style) => theme.space[0]}px;\n left: 50%;\n transform: translate3d(-50%, 0, 0);\n background: var(--component-bg);\n border-radius: ${({theme}: Style) => theme.radius[2]}px;\n padding: ${({theme}: Style) => theme.space[2]}px;\n z-index: 1000;\n\n &:empty {\n display: none;\n }\n`\n\nexport const Legend: React.FC<Style> = styled.div`\n color: #ccc;\n position: absolute;\n top: ${({theme}: Style) => theme.space[4]}px;\n left: ${({theme}: Style) => theme.space[4]}px;\n\n & > div {\n margin: 5px 0;\n }\n`\n\nexport const LegendRow = styled.div`\n display: flex;\n`\n\nexport const LegendBadge: React.FC<Style> = styled.div`\n width: 1.25em;\n height: 1.25em;\n background: currentColor;\n border-radius: 50%;\n margin-right: ${({theme}: Style) => theme.space[2]}px;\n`\n","import {useEffect} from 'react'\n\nimport type {ListenEvent, ListenOptions, SanityClient} from '@sanity/client'\n\nexport function useListen(\n query: string,\n params: {[key: string]: any},\n options: ListenOptions,\n onUpdate: (event: ListenEvent<any>) => void,\n dependencies: unknown[],\n client: SanityClient,\n): void {\n useEffect(() => {\n const subscription = client.listen(query, params, options).subscribe((update) => {\n onUpdate(update)\n })\n return () => {\n subscription.unsubscribe()\n }\n }, [...dependencies, client])\n}\n\nexport function useFetchDocuments(\n query: string,\n onFetch: (event: ListenEvent<any>) => void,\n dependencies: unknown[],\n client: SanityClient,\n): void {\n useEffect(() => {\n void client.fetch(query).then((result) => {\n onFetch(result)\n })\n }, [...dependencies, client])\n}\n","export function sizeOf(value: any): number {\n if (value === null) {\n return 0\n }\n\n if (typeof value === 'object') {\n return Object.entries(value).reduce((total, [k, v]) => total + sizeOf(k) + sizeOf(v), 0)\n }\n\n if (Array.isArray(value)) {\n return Object.entries(value).reduce((total, v) => total + sizeOf(v), 0)\n }\n\n if (typeof value === 'string') {\n return value.length\n }\n\n return 1\n}\n\nexport function loadImage(url: string, w: number, h: number): Promise<HTMLImageElement | null> {\n return new Promise((resolve) => {\n const img = new Image(w, h)\n img.onload = () => {\n resolve(img)\n }\n img.onerror = (event) => {\n console.log('Image error', event)\n resolve(null)\n }\n img.src = url\n })\n}\n\nexport function sortBy<T>(array: T[], f: (t: T) => number): T[] {\n return array.sort((a, b) => {\n const va = f(a)\n const vb = f(b)\n return va < vb ? -1 : va > vb ? 1 : 0\n })\n}\n\nexport function truncate(s: string, limit: number): string {\n if (s.length > limit) {\n return `${s.substring(0, limit)}…`\n }\n return s\n}\n","import BezierEasing from 'bezier-easing'\nimport deepEqual from 'deep-equal'\nimport {rgba} from 'polished'\nimport React, {useCallback, useEffect, useState} from 'react'\nimport {ForceGraph2D} from 'react-force-graph'\nimport {useClient, useUserColorManager} from 'sanity'\nimport {useRouter} from 'sanity/router'\nimport {v4 as uuidv4} from 'uuid'\n\nimport type {SanityDocument, SanityClient} from '@sanity/client'\n\nimport {black, COLOR_HUES, gray, white, hues} from '@sanity/color'\nimport {useTheme} from '@sanity/ui'\n\nimport {GraphRoot, GraphWrapper, HoverNode, Legend, LegendBadge, LegendRow} from './GraphViewStyle'\nimport {useFetchDocuments, useListen} from './hooks'\nimport {sortBy, loadImage, sizeOf, truncate} from './utils'\n\nconst DEFAULT_QUERY = `\n *[\n !(_id in path(\"_.*\")) &&\n !(_type match \"system.*\") &&\n !(_type match \"sanity.*\")\n ]\n`\n\nconst fadeEasing = BezierEasing(0, 0.9, 1, 1)\nconst softEasing = BezierEasing(0.25, 0.1, 0.0, 1.0)\nconst idleTimeout = 10000\nconst imageSize = 40\n\nfunction getTopDocTypes(counts: Record<string, number>) {\n return sortBy(Object.keys(counts), (docType) => counts[docType] || 0)\n .reverse()\n .slice(0, 10)\n}\n\nfunction formatDocType(docType: string) {\n return (docType.substring(0, 1).toUpperCase() + docType.substring(1))\n .replace(/\\./g, ' ')\n .replace(/[A-Z]/g, ' $&')\n .trim()\n}\n\nfunction getDocTypeCounts(docs: SanityDocument[]) {\n const types: Record<string, number> = {}\n for (const doc of docs) {\n types[doc._type] = (types[doc._type] || 0) + 1\n }\n return types\n}\n\nfunction labelFor(doc: SanityDocument) {\n return `${doc.title || doc.name || doc._id}`.trim()\n}\n\nfunction valueFor(doc: any, maxSize: number) {\n return 5 + 100 * (sizeOf(doc) / maxSize)\n}\n\nfunction findRefs(obj: any, dest: any[] = []) {\n if (obj !== null) {\n if (typeof obj === 'object') {\n for (const [k, v] of Object.entries(obj)) {\n if (k === '_ref' && typeof v === 'string' && v.length > 0) {\n dest.push(stripDraftId(v))\n }\n findRefs(v, dest)\n }\n } else if (Array.isArray(obj)) {\n for (const v of obj) {\n findRefs(v, dest)\n }\n }\n }\n return dest\n}\n\nfunction stripDraftId(id: string) {\n return id.replace(/^drafts\\./, '')\n}\n\nfunction deduplicateDrafts(docs: SanityDocument[]) {\n const deduped: Record<string, SanityDocument> = {}\n for (const doc of docs) {\n if (!doc._id.startsWith('drafts.')) {\n deduped[doc._id] = doc\n }\n }\n for (const doc of docs) {\n if (doc._id.startsWith('drafts.')) {\n const id = stripDraftId(doc._id)\n deduped[id] = Object.assign(doc, {_id: id})\n }\n }\n return Object.values(deduped)\n}\n\nclass Users {\n _users: any[] = []\n\n async getById(id: string, client: SanityClient) {\n let user = this._users.find((u) => u._id === id)\n if (!user) {\n user = await client.users.getById(id)\n this._users.push(user)\n user.image = await loadImage(\n user.imageUrl ||\n 'https://raw.githubusercontent.com/sanity-io/sanity-plugin-graph-view/main/assets/head-silhouette.jpg',\n imageSize,\n imageSize,\n )\n }\n return user\n }\n}\n\nclass Session {\n id: string | null = null\n user: any = null\n doc: SanityDocument | null = null\n lastActive: number = 0\n startTime: number = 0\n angle: number = 0\n}\n\nclass GraphData {\n sessions: Session[] = []\n data: any\n\n constructor(docs: SanityDocument[] = []) {\n const docsById: Record<string, SanityDocument> = {}\n for (const doc of docs) {\n docsById[doc._id] = doc\n }\n\n this.data = {\n nodes: docs.map((d) => Object.assign({id: d._id, type: 'document', doc: d})),\n links: docs\n .flatMap((doc) => findRefs(doc).map((ref) => ({source: doc._id, target: ref})))\n .filter((link) => docsById[link.source] && docsById[link.target]),\n }\n }\n\n setSession(user: any, docNode: any) {\n let session = this.sessions.find((s) => s.user.id === user.id && s.doc?._id === docNode.doc._id)\n if (!session) {\n session = new Session()\n session.id = uuidv4()\n session.user = user\n session.startTime = Date.now()\n session.doc = docNode.doc\n session.angle = Math.random() * 2 * Math.PI\n this.sessions.push(session)\n }\n session.lastActive = Date.now()\n }\n\n reapSessions() {\n for (let i = 0; i < this.sessions.length; i++) {\n const session = this.sessions[i]\n if (Date.now() - session.lastActive > idleTimeout) {\n this.sessions = [...this.sessions.slice(0, i), ...this.sessions.slice(i + 1)]\n i--\n }\n }\n }\n\n clone() {\n const copy = new GraphData()\n Object.assign(copy, this)\n copy.data = {\n nodes: [...this.data.nodes],\n links: [...this.data.links],\n }\n return copy\n }\n}\n\nconst users = new Users()\n\ninterface GraphViewConfig {\n query?: string\n /** default: '2022-09-01' */\n apiVersion?: string\n}\n\nexport function GraphView(props: GraphViewConfig) {\n const query = props.query || DEFAULT_QUERY\n const apiVersion = props.apiVersion ?? '2022-09-01'\n\n const userColorManager = useUserColorManager()\n const [maxSize, setMaxSize] = useState(0)\n const [hoverNode, setHoverNode] = useState<any>(null)\n const [documents, setDocuments] = useState<SanityDocument[]>([])\n const [docTypes, setDocTypes] = useState<Record<string, number>>({})\n const [graph, setGraph] = useState(() => new GraphData())\n const router = useRouter()\n const client = useClient({apiVersion})\n\n const fetchCallback = useCallback((_docs: any) => {\n const docs = deduplicateDrafts(_docs)\n setMaxSize(Math.max(...docs.map(sizeOf)))\n setDocuments(docs)\n setDocTypes(getDocTypeCounts(docs))\n setGraph(new GraphData(docs))\n }, [])\n\n const listenCallback = useCallback(\n async (update: any) => {\n const doc = update.result\n if (doc) {\n doc._id = stripDraftId(doc._id)\n\n const docsById: Record<string, SanityDocument> = {}\n for (const d of documents) {\n docsById[d._id] = d\n }\n\n let oldDoc\n const docs = [...documents]\n const idx = documents.findIndex((d) => d._id === doc._id)\n if (idx >= 0) {\n oldDoc = docs[idx]\n docs[idx] = doc\n } else {\n docs.push(doc)\n }\n setDocuments(docs)\n setDocTypes(getDocTypeCounts(docs))\n setMaxSize(Math.max(...docs.map(sizeOf)))\n\n const newGraph = graph.clone()\n\n const oldRefs = findRefs(oldDoc || {}).filter(\n (id) => id === doc._id || docsById[id] !== null,\n )\n const newRefs = findRefs(doc).filter((id) => id === doc._id || docsById[id] !== null)\n\n let graphChanged = !deepEqual(oldRefs, newRefs)\n if (graphChanged) {\n newGraph.data.links = newGraph.data.links\n .filter((l: any) => l.source.id !== doc._id)\n .concat(newRefs.map((ref) => ({source: doc._id, target: ref})))\n }\n\n let docNode\n const nodeIdx = graph.data.nodes.findIndex((n: any) => n.doc && n.doc._id === doc._id)\n if (nodeIdx >= 0) {\n docNode = graph.data.nodes[nodeIdx]\n docNode.doc = doc\n } else {\n docNode = {id: doc._id, type: 'document', doc: doc}\n newGraph.data.nodes.push(docNode)\n graphChanged = true\n }\n if (graphChanged) {\n setGraph(newGraph)\n }\n\n // @ts-expect-error - TODO: fix this\n const user = await users.getById(update.identity, client)\n graph.setSession(user, docNode)\n } else if (update.transition === 'disappear') {\n const docId = stripDraftId(update.documentId)\n\n const docs = documents.filter((d) => d._id !== docId)\n setDocuments(docs)\n setDocTypes(getDocTypeCounts(docs))\n setMaxSize(Math.max(...docs.map(sizeOf)))\n\n const newGraph = graph.clone()\n newGraph.data.links = newGraph.data.links.filter(\n (l: any) => l.source.id !== docId && l.target.id !== docId,\n )\n newGraph.data.nodes = newGraph.data.nodes.filter((n: any) => n.id !== docId)\n setGraph(newGraph)\n }\n },\n [documents, graph, client],\n )\n // @ts-expect-error - TODO: fix this\n useFetchDocuments(query, fetchCallback, [], client)\n // @ts-expect-error - TODO: fix this\n useListen(query, {}, {}, listenCallback, [documents, graph], client)\n useEffect(() => {\n const interval = setInterval(() => graph.reapSessions(), 1000)\n return () => clearInterval(interval)\n }, [graph])\n\n const theme = useTheme().sanity\n\n return (\n <GraphWrapper theme={theme}>\n <GraphRoot theme={theme}>\n <Legend theme={theme}>\n {getTopDocTypes(docTypes).map((docType) => (\n <LegendRow\n className={'legend__row'}\n key={docType}\n style={{color: getDocTypeColor(docType).fill}}\n >\n <LegendBadge theme={theme} />\n <div>{formatDocType(docType)}</div>\n </LegendRow>\n ))}\n </Legend>\n {hoverNode && <HoverNode theme={theme}>{labelFor(hoverNode.doc)}</HoverNode>}\n\n {/* @ts-expect-error - TODO: fix this */}\n <ForceGraph2D\n graphData={graph.data}\n nodeAutoColorBy=\"group\"\n enableNodeDrag={false}\n onNodeHover={(node: any) => setHoverNode(node)}\n onNodeClick={(node: any) => {\n router.navigateIntent('edit', {id: node.doc._id, documentType: node.doc._type})\n }}\n linkColor={() => rgba(gray[500].hex, 0.25)}\n nodeLabel={() => ''}\n nodeRelSize={1}\n nodeVal={(node: any) => valueFor(node.doc, maxSize)}\n onRenderFramePost={(ctx, globalScale) => {\n for (const session of graph.sessions) {\n const node = graph.data.nodes.find(\n (n: any) => n.doc && n.doc._id === session?.doc?._id,\n )\n if (node) {\n const idleFactorRange = idleTimeout\n const angle = session.angle\n const radius = Math.sqrt(valueFor(node.doc, maxSize))\n const image = session.user.image\n const userColor = userColorManager.get(session.user.displayName).tints[400].hex\n const distance = radius * globalScale + 40\n const imgW = image ? image.width : 0\n const imgH = image ? image.height : 0\n const x = node.x + (Math.sin(angle) * distance) / globalScale\n const y = node.y + (Math.cos(angle) * distance) / globalScale\n\n ctx.save()\n try {\n ctx.globalAlpha = fadeEasing(\n 1 -\n Math.min(idleFactorRange, Date.now() - session.lastActive) / idleFactorRange,\n )\n ctx.font = `bold ${Math.round(12 / globalScale)}px sans-serif`\n\n ctx.beginPath()\n ctx.strokeStyle = rgba(white.hex, 1.0)\n ctx.lineWidth = 2 / globalScale\n ctx.moveTo(\n node.x + (Math.sin(angle) * (distance - imgW / 2)) / globalScale,\n node.y + (Math.cos(angle) * (distance - imgH / 2)) / globalScale,\n )\n ctx.lineTo(node.x + Math.sin(angle) * radius, node.y + Math.cos(angle) * radius)\n ctx.stroke()\n\n ctx.beginPath()\n ctx.strokeStyle = rgba(white.hex, 1.0)\n ctx.lineWidth = 2 / globalScale\n ctx.arc(node.x, node.y, radius, 0, 2 * Math.PI, false)\n ctx.stroke()\n\n if (image) {\n ctx.save()\n try {\n const dur = 700\n const f = softEasing(\n Math.max(0, (dur - (Date.now() - session.startTime)) / dur),\n )\n if (f > 0) {\n ctx.beginPath()\n ctx.fillStyle = rgba(userColor, f)\n ctx.arc(x, y, (imgW / 2 + 10) / globalScale, 0, 2 * Math.PI, false)\n ctx.fill()\n }\n\n ctx.beginPath()\n ctx.fillStyle = rgba(white.hex, 1.0)\n ctx.arc(x, y, imgW / globalScale / 2, 0, 2 * Math.PI, false)\n ctx.clip()\n\n ctx.drawImage(\n image,\n x - imgW / globalScale / 2,\n y - imgH / globalScale / 2,\n imgW / globalScale,\n imgH / globalScale,\n )\n\n ctx.strokeStyle = black.hex\n ctx.lineWidth = 6 / globalScale\n ctx.stroke()\n\n ctx.strokeStyle = userColor\n ctx.lineWidth = 4 / globalScale\n ctx.stroke()\n } finally {\n ctx.restore()\n }\n }\n\n ctx.beginPath()\n ctx.strokeStyle = rgba(black.hex, 1)\n ctx.lineWidth = 0.5 / globalScale\n ctx.arc(x, y, imgW / globalScale / 2, 0, 2 * Math.PI, false)\n ctx.stroke()\n\n const above = angle >= Math.PI / 2 && angle < Math.PI * 1.5\n const textY = above\n ? y - (imgH / 2 + 5) / globalScale\n : y + (imgH / 2 + 5) / globalScale\n ctx.fillStyle = rgba(white.hex, 1.0)\n ctx.textAlign = 'center'\n ctx.textBaseline = above ? 'bottom' : 'top'\n ctx.fillText(session.user.displayName, x, textY)\n } finally {\n ctx.restore()\n }\n }\n }\n }}\n nodeCanvasObject={(node: any, ctx, globalScale) => {\n switch (node.type) {\n case 'document': {\n const nodeColor = getDocTypeColor(node.doc._type)\n const radius = Math.sqrt(valueFor(node.doc, maxSize))\n const fontSize = Math.min(100, 10.0 / globalScale)\n\n ctx.beginPath()\n ctx.fillStyle =\n hoverNode !== null && node.doc._id === hoverNode.doc._id\n ? rgba(gray[500].hex, 0.8)\n : nodeColor.fill\n ctx.strokeStyle = nodeColor.border\n ctx.lineWidth = 0.5\n ctx.arc(node.x, node.y, radius, 0, 2 * Math.PI, false)\n ctx.stroke()\n ctx.fill()\n\n if (radius * globalScale > 10) {\n ctx.font = `${fontSize}px sans-serif`\n const w = radius * 2 + 30 / globalScale\n for (let len = 50; len >= 5; len /= 1.2) {\n const label = truncate(labelFor(node.doc), Math.round(len))\n const textMetrics = ctx.measureText(label)\n if (textMetrics.width < w) {\n // ctx.fillStyle = rgba(color.white.hex, 1.0)\n ctx.textAlign = 'center'\n ctx.textBaseline = 'top'\n\n ctx.strokeStyle = rgba(black.hex, 0.5)\n ctx.lineWidth = 2 / globalScale\n ctx.strokeText(label, node.x, node.y + radius + 5 / globalScale)\n\n ctx.fillText(label, node.x, node.y + radius + 5 / globalScale)\n break\n }\n }\n }\n }\n }\n }}\n linkCanvasObject={(link: any, ctx, globalScale) => {\n ctx.beginPath()\n ctx.strokeStyle = rgba(gray[500].hex, 0.125)\n ctx.lineWidth = 2 / globalScale\n ctx.moveTo(link.source.x, link.source.y)\n ctx.lineTo(link.target.x, link.target.y)\n ctx.stroke()\n }}\n />\n </GraphRoot>\n </GraphWrapper>\n )\n}\n\nconst colorCache: Record<string, {fill: string; border: string}> = {}\nlet typeColorNum = 0\n\nfunction getDocTypeColor(docType: any) {\n if (colorCache[docType]) {\n return colorCache[docType]\n }\n\n const hue = COLOR_HUES[typeColorNum % COLOR_HUES.length]\n\n typeColorNum += 1\n\n colorCache[docType] = {\n fill: hues[hue][400].hex,\n border: rgba(black.hex, 0.5),\n }\n\n return colorCache[docType]\n}\n","import React from 'react'\n\n/**\n * Couple of things to note:\n * - width and height is set to 1em\n * - fill is `currentColor` - this will ensure that the icon looks uniform and\n * that the hover/active state works. You can of course render anything you\n * would like here, but for plugins that are to be used in more than one\n * studio, we suggest these rules are followed\n **/\nexport const GraphViewIcon = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1em\" height=\"1em\" viewBox=\"0 0 46.063 46.063\">\n <path\n fill=\"currentColor\"\n d=\"M18.022 38.676v2.813h-1.21q-4.864 0-6.525-1.447-1.64-1.445-1.64-5.762v-4.666q0-2.95-1.055-4.083-1.055-1.13-3.828-1.13h-1.19v-2.794h1.19q2.793 0 3.828-1.114 1.055-1.132 1.055-4.043V11.76q0-4.316 1.64-5.742 1.66-1.446 6.524-1.446h1.212v2.793h-1.328q-2.754 0-3.594.86-.84.86-.84 3.613v4.844q0 3.066-.898 4.453-.88 1.387-3.028 1.875 2.168.527 3.047 1.914.88 1.387.88 4.434v4.843q0 2.754.84 3.614.84.86 3.594.86h1.328zM28.04 38.676h1.368q2.735 0 3.555-.84.84-.84.84-3.633V29.36q0-3.047.88-4.434.878-1.387 3.046-1.914-2.17-.488-3.048-1.875-.88-1.387-.88-4.453V11.84q0-2.773-.84-3.613-.82-.86-3.554-.86H28.04V4.574h1.232q4.863 0 6.484 1.446 1.64 1.426 1.64 5.742v4.687q0 2.91 1.055 4.042 1.056 1.114 3.83 1.114h1.21V24.4h-1.21q-2.774 0-3.83 1.13-1.053 1.134-1.053 4.084v4.667q0 4.318-1.64 5.763-1.622 1.446-6.485 1.446h-1.23v-2.814z\"\n />\n </svg>\n)\n","import React from 'react'\nimport {definePlugin} from 'sanity'\nimport {route} from 'sanity/router'\n\nimport {GraphView} from './tool/GraphView'\nimport {GraphViewIcon} from './tool/GraphViewIcon'\n\nexport interface GraphViewConfig {\n query?: string\n}\n\nexport const contentGraphView = definePlugin<GraphViewConfig>((config: GraphViewConfig = {}) => {\n return {\n name: '@sanity/content-graph-view',\n\n tools: (prev) => {\n return [\n ...prev,\n {\n name: 'graph-your-content',\n title: 'Graph',\n icon: GraphViewIcon,\n component: function component() {\n return <GraphView {...config} />\n },\n router: route.create('/:selectedDocumentId'),\n },\n ]\n },\n }\n})\n"],"names":["styled","black","useEffect","BezierEasing","uuidv4","useUserColorManager","useState","router","useRouter","useClient","useCallback","deepEqual","useTheme","jsx","jsxs","ForceGraph2D","rgba","gray","white","COLOR_HUES","hues","definePlugin","route"],"mappings":"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"}
|
package/dist/index.d.cts
ADDED